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

相关文章

在C#中获取端口号与系统信息的高效实践

《在C#中获取端口号与系统信息的高效实践》在现代软件开发中,尤其是系统管理、运维、监控和性能优化等场景中,了解计算机硬件和网络的状态至关重要,C#作为一种广泛应用的编程语言,提供了丰富的API来帮助开... 目录引言1. 获取端口号信息1.1 获取活动的 TCP 和 UDP 连接说明:应用场景:2. 获取硬

关于@MapperScan和@ComponentScan的使用问题

《关于@MapperScan和@ComponentScan的使用问题》文章介绍了在使用`@MapperScan`和`@ComponentScan`时可能会遇到的包扫描冲突问题,并提供了解决方法,同时,... 目录@MapperScan和@ComponentScan的使用问题报错如下原因解决办法课外拓展总结@

MybatisGenerator文件生成不出对应文件的问题

《MybatisGenerator文件生成不出对应文件的问题》本文介绍了使用MybatisGenerator生成文件时遇到的问题及解决方法,主要步骤包括检查目标表是否存在、是否能连接到数据库、配置生成... 目录MyBATisGenerator 文件生成不出对应文件先在项目结构里引入“targetProje

C#使用HttpClient进行Post请求出现超时问题的解决及优化

《C#使用HttpClient进行Post请求出现超时问题的解决及优化》最近我的控制台程序发现有时候总是出现请求超时等问题,通常好几分钟最多只有3-4个请求,在使用apipost发现并发10个5分钟也... 目录优化结论单例HttpClient连接池耗尽和并发并发异步最终优化后优化结论我直接上优化结论吧,

Java内存泄漏问题的排查、优化与最佳实践

《Java内存泄漏问题的排查、优化与最佳实践》在Java开发中,内存泄漏是一个常见且令人头疼的问题,内存泄漏指的是程序在运行过程中,已经不再使用的对象没有被及时释放,从而导致内存占用不断增加,最终... 目录引言1. 什么是内存泄漏?常见的内存泄漏情况2. 如何排查 Java 中的内存泄漏?2.1 使用 J

Python MySQL如何通过Binlog获取变更记录恢复数据

《PythonMySQL如何通过Binlog获取变更记录恢复数据》本文介绍了如何使用Python和pymysqlreplication库通过MySQL的二进制日志(Binlog)获取数据库的变更记录... 目录python mysql通过Binlog获取变更记录恢复数据1.安装pymysqlreplicat

C#实现获取电脑中的端口号和硬件信息

《C#实现获取电脑中的端口号和硬件信息》这篇文章主要为大家详细介绍了C#实现获取电脑中的端口号和硬件信息的相关方法,文中的示例代码讲解详细,有需要的小伙伴可以参考一下... 我们经常在使用一个串口软件的时候,发现软件中的端口号并不是普通的COM1,而是带有硬件信息的。那么如果我们使用C#编写软件时候,如

numpy求解线性代数相关问题

《numpy求解线性代数相关问题》本文主要介绍了numpy求解线性代数相关问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 在numpy中有numpy.array类型和numpy.mat类型,前者是数组类型,后者是矩阵类型。数组

解决systemctl reload nginx重启Nginx服务报错:Job for nginx.service invalid问题

《解决systemctlreloadnginx重启Nginx服务报错:Jobfornginx.serviceinvalid问题》文章描述了通过`systemctlstatusnginx.se... 目录systemctl reload nginx重启Nginx服务报错:Job for nginx.javas

C#实现WinForm控件焦点的获取与失去

《C#实现WinForm控件焦点的获取与失去》在一个数据输入表单中,当用户从一个文本框切换到另一个文本框时,需要准确地判断焦点的转移,以便进行数据验证、提示信息显示等操作,本文将探讨Winform控件... 目录前言获取焦点改变TabIndex属性值调用Focus方法失去焦点总结最后前言在一个数据输入表单