引用自: http://www.zicheng.net/article/982028.htm

目前基于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数据。

最终这个问题的解决方案是把request.getInputStream()放到string id= request.getParameter("id");之前,这样就回避了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 体用流读取为空的问题的更多相关文章

  1. servlet 获取 post body 体用流读取为空的问题【转】

    引用自: http://www.zicheng.net/article/982028.htm 目前基于rest风格的很多API开始使用通过body data来传输来代替之前的key-value传输方式 ...

  2. java HttpServletRequest 重复流读取

    在用reset接口的时候,常常会使用request.getInputStream()方法,但是流只能读取一次,一旦想要加上一个过滤器用来检测用户请求的数据时就会出现异常.   在过滤器中通过流读取出用 ...

  3. java HttpServletRequest 重复流读取

    在用reset接口的时候,常常会使用request.getInputStream()方法,但是流只能读取一次,一旦想要加上一个过滤器用来检测用户请求的数据时就会出现异常.   在过滤器中通过流读取出用 ...

  4. java IO流读取图片供前台显示

    最近项目中需要用到IO流来读取图片以提供前台页面展示,由于以前一直是用url路径的方式进行图片展示,一听说要项目要用IO流读取图片感觉好复杂一样,但任务下达下来了,做为程序员只有选择去执行喽,于是找了 ...

  5. servlet获取参数时,request.getParameter("id")参数获取失败

    servlet获取参数时,request.getParameter("id")参数获取失败,这里的参数是“index”里面href中的参数 要注意,取不到值,是不是要取的参数有没有 ...

  6. Servlet获取URL地址

    这里来说说用Servlet获取URL地址.在HttpServletRequest类里,有以下六个取URL的函数: getContextPath 取得项目名 getServletPath 取得Servl ...

  7. paip.获取proxool的配置 xml读取通过jdk xml 初始化c3c0在代码中总结

    paip.获取proxool的配置  xml读取通过jdk xml 初始化c3c0在代码中  xml读取通过jdk xml 初始化c3c0在代码中.. ... 作者Attilax  艾龙,  EMAI ...

  8. JavaWeb学习记录(八)——servlet获取配置信息

    jdbc.properties内容如下: jdbcUrl=jdbc\:mysql\://localhost\:3306/animaluser=rootpass=root servlet获取资源信息代码 ...

  9. Servlet 获取IllegelStateException

    Servlet 获取IllegelStateException: response提交之后,进行requestDispatcher.forwar(),会产生这样的问题: 但是必须是outputStre ...

随机推荐

  1. appium移动端测试之滑动(二)

    在ios测试中,需要用到滑动,所以用java封装了一套滑动的方法,不多说,贴代码 /** * 上滑1/4屏幕 */ public void slideUP1_4() { int x = driver. ...

  2. 关于android.view.WindowManager$BadTokenException问题出现以及解决的一些记录

    1.出现 在app showdialog()时偶尔会出现,根据stackoverflow.com的描述,貌似是show的时候用作context的activity以及destroy了,,,一些异步操作会 ...

  3. IP地址

    if (!/^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])(\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])){3}$/.test($.trim($('#add ...

  4. java写入excel文件poi

    java写入excel文件 java写入excel文件poi,支持xlsx与xls,没有文件自动创建 package com.utils; import java.io.File; import ja ...

  5. linux VI search command 搜索 加入行号

    VI COMMAND:set number :set nonumber VI COMMAND/keywork   //search

  6. JAVA新手笔记 Intent对象和Bundle对象

    Intent对象和Bundle对象 功能主要是在 MainActivity中定义了2个EditText,当用户输入内容,把他传入到第二个活动, 自己新创的活动中,MyActivity中 放在MainA ...

  7. DVD管理器集合版

    利用所学的集合写出的DVD管理系统,运用到了所学到集合基础. import java.text.ParseException; import java.text.SimpleDateFormat; i ...

  8. 关于Core Animation(转载部分内容)

    读者在浏览技术博客的时候,看到一篇关于Core Animation的介绍,觉得挺有用的,想分享给大家.原作者不知道是谁,嘿,所以就先不标注了,如有冒犯敬请原谅.不过笔者从中摘录部分内容分享一下. 其中 ...

  9. js对象常用2中构造方法

    //js 对象的构造方法通常有2中情况: //第一种是通过json对象构造 var persion={ name:"孙悟空", age:40, eat:function () { ...

  10. 如何使用THashedStringList

    1.添加 uses system.IniFiles 2.实例代码: unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System ...