Servlet 获取 post body 体 (用流读取为空的问题)

2024-06-10 02:18

本文主要是介绍Servlet 获取 post body 体 (用流读取为空的问题),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

原文链接:http://www.itbus.tech/detail.html?id=8745

目前基于rest风格的很多API开始使用通过body data来传输来代替之前的key-value传输方式。在Java servlet或者springmvc中可以通过如下代码来获取并图片通过流方式传输的数据:

InputStream is= null; String contentStr="";
try {is = request.getInputStream();contentStr= IOUtils.toString(is, "utf-8");} catch (IOException e) {e.printStackTrace();}

单纯的如上代码可以获取通过POST或PUT等方法传输的数据,但有时候也有例,如果你现在有如下请求的时候:

POST http://127.0.0.1:8085/test?id=12564564654
POST data:
01001512a101a203a303a

可以看到这里不但会通过post data流的方式发送数据,同时也通过key-value发送了数据,那现在的代码是什么样的呢?如下:

@RequestMapping(value = "posttest", method = RequestMethod.POST) 
@ResponseBody 
public String test(HttpServletRequest request,@RequestParam(value = "id") String id ) {InputStream is= null;String contentStr="";try {         is = request.getInputStream();contentStr= IOUtils.toString(is, "utf-8");} catch (IOException e) {e.printStackTrace();}return contentStr;
}

通过测试你会发现contentStr中并未获取到任何值,同时也不会报任务错误,这是怎么回事呢?会不会是springmvc的问题?答案是否定的。这个时候获取不到postdata的数据与springmvc没有任务关系,同样的把上面的代码进行修改,如下:

@RequestMapping(value = "posttest", method = RequestMethod.POST) 
@ResponseBody
public String test(HttpServletRequest request) {String id=request.getParameter("id");InputStream is= null;String contentStr="";try { is = request.getInputStream();contentStr= IOUtils.toString(is, "utf-8");} catch (IOException e) {e.printStackTrace();}return contentStr;
}

经过测试getInputStream仍然没有数据。

那问题出在哪呢?经过查找终于找到问了问答的原因,答案在servlet规范中:

3.1.1 When Parameters Are Available
The following are the conditions that mustbe met before post form data will be
populated to the parameter set:
1. The request is an HTTP or HTTPS request.
2. The HTTP method is POST.
3. The content type is application/x-www-form-urlencoded.
4. The servlet has made an initial call of any of the getParameterfamily of methods
on the request object.
If the conditions are not met and the post form data is not included in the parameter
set, the post data must still be available to the servlet via the request object’s input
stream. If the conditions are met, post form data will no longer be available for
reading directly from the request object’s input stream.

经过翻译servlet上面一段规范如下:

根据Servlet规范,如果同时满足下列条件,则请求体(Entity)中的表单数据,将被填充到request的parameter集合中(request.getParameter系列方法可以读取相关数据):
1 这是一个HTTP/HTTPS请求
2 请求方法是POST(querystring无论是否POST都将被设置到parameter中)
3 请求的类型(Content-Type头)是application/x-www-form-urlencoded
4 Servlet调用了getParameter系列方法

如果上述条件没有同时满足,则相关的表单数据不会被设置进request的parameter集合中,相关的数据可以通过request.getInputStream()来访问。反之,如果上述条件均满足,相关的表单数据将不能再通过request.getInputStream()来读取。

根据这个规范的说明,当我们在调用request.getParameter(“id”)的方法时,通过post data交的数据(请求体)被填充到了parameter集合中了,所以后面的通过request.getInputStream获取数据流时就为空。通过测试打印断点我们可以看到如下图:
原本我们只提交了一个参数id,但是在执行过request.getParameter(“id”)的方法后,我们的parameterNames里就有了两个参数,其中第二个参数的key就是我们通过body请求体传输的数据,值也是body请求体的post data数据。

最终这个问题的解决方案是把string id= request.getParameter(“id”);放到request.getInputStream之后,这样就回避了servlet的规范,代码调整后为:

@RequestMapping(value = "posttest", method = RequestMethod.POST) 
@ResponseBody
public String test(HttpServletRequest request) {InputStream is= null;String contentStr="";try {is = request.getInputStream();contentStr= IOUtils.toString(is, "utf-8");} catch (IOException e) {e.printStackTrace();}String id=request.getParameter("id");return contentStr;
}

在servlet规范中已经说明是post请求时才会有这个获取post提交数据的顺序问题,而在其它的如put中不会出现这种顺序问题。

这篇关于Servlet 获取 post body 体 (用流读取为空的问题)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1046954

相关文章

好题——hdu2522(小数问题:求1/n的第一个循环节)

好喜欢这题,第一次做小数问题,一开始真心没思路,然后参考了网上的一些资料。 知识点***********************************无限不循环小数即无理数,不能写作两整数之比*****************************(一开始没想到,小学没学好) 此题1/n肯定是一个有限循环小数,了解这些后就能做此题了。 按照除法的机制,用一个函数表示出来就可以了,代码如下

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

购买磨轮平衡机时应该注意什么问题和技巧

在购买磨轮平衡机时,您应该注意以下几个关键点: 平衡精度 平衡精度是衡量平衡机性能的核心指标,直接影响到不平衡量的检测与校准的准确性,从而决定磨轮的振动和噪声水平。高精度的平衡机能显著减少振动和噪声,提高磨削加工的精度。 转速范围 宽广的转速范围意味着平衡机能够处理更多种类的磨轮,适应不同的工作条件和规格要求。 振动监测能力 振动监测能力是评估平衡机性能的重要因素。通过传感器实时监

缓存雪崩问题

缓存雪崩是缓存中大量key失效后当高并发到来时导致大量请求到数据库,瞬间耗尽数据库资源,导致数据库无法使用。 解决方案: 1、使用锁进行控制 2、对同一类型信息的key设置不同的过期时间 3、缓存预热 1. 什么是缓存雪崩 缓存雪崩是指在短时间内,大量缓存数据同时失效,导致所有请求直接涌向数据库,瞬间增加数据库的负载压力,可能导致数据库性能下降甚至崩溃。这种情况往往发生在缓存中大量 k

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

【VUE】跨域问题的概念,以及解决方法。

目录 1.跨域概念 2.解决方法 2.1 配置网络请求代理 2.2 使用@CrossOrigin 注解 2.3 通过配置文件实现跨域 2.4 添加 CorsWebFilter 来解决跨域问题 1.跨域概念 跨域问题是由于浏览器实施了同源策略,该策略要求请求的域名、协议和端口必须与提供资源的服务相同。如果不相同,则需要服务器显式地允许这种跨域请求。一般在springbo

题目1254:N皇后问题

题目1254:N皇后问题 时间限制:1 秒 内存限制:128 兆 特殊判题:否 题目描述: N皇后问题,即在N*N的方格棋盘内放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在同一斜线上。因为皇后可以直走,横走和斜走如下图)。 你的任务是,对于给定的N,求出有多少种合法的放置方法。输出N皇后问题所有不同的摆放情况个数。 输入

vscode中文乱码问题,注释,终端,调试乱码一劳永逸版

忘记咋回事突然出现了乱码问题,很多方法都试了,注释乱码解决了,终端又乱码,调试窗口也乱码,最后经过本人不懈努力,终于全部解决了,现在分享给大家我的方法。 乱码的原因是各个地方用的编码格式不统一,所以把他们设成统一的utf8. 1.电脑的编码格式 开始-设置-时间和语言-语言和区域 管理语言设置-更改系统区域设置-勾选Bata版:使用utf8-确定-然后按指示重启 2.vscode

matlab读取NC文件(含group)

matlab读取NC文件(含group): NC文件数据结构: 代码: % 打开 NetCDF 文件filename = 'your_file.nc'; % 替换为你的文件名% 使用 netcdf.open 函数打开文件ncid = netcdf.open(filename, 'NC_NOWRITE');% 查看文件中的组% 假设我们想读取名为 "group1" 的组groupName

Android Environment 获取的路径问题

1. 以获取 /System 路径为例 /*** Return root of the "system" partition holding the core Android OS.* Always present and mounted read-only.*/public static @NonNull File getRootDirectory() {return DIR_ANDR