开发环境: JDK7, Tomcat7.0.54, Spring3.2.6
问题描述:
客户端: (外部系统)通过HTTP的POST方法提交了一个XML给我
但是请求头 Content-Type 被设置成了 application/x-www-form-urlencoded (浏览器form表单提交的默认编码类型)
也就是说, 请求的正文不是 &key1=value1&key2=value2 这样的格式 而是xml内容: <?xml version="1.0" encoding="GBK"?><data><msg>test</msg></data>
代码类似于:
服务端:通过request.getInputStream()获取到流, 然后读取流来获得POST过来的xml
但是, 就是获取到的xml却为空, 为什么?
代码类似于:
于是到处找原因啊,找啊找啊找不到...................................
然后输出了下客户端请求是的Content-Type头,发现居然是application/x-www-form-urlencoded你这不是坑我吗~~~~~~~~~~~~~~~~~
马上联想到 reqeust.getParam* 一系列方法, 对于表单提交的字段, 可以通过这个方法来获取到, 但是原始的POST正文都是 &key1=value1&key2=value2 这种形式
于是猜想: 肯定是Tomcat帮我们做了解析, 一解析的话, 肯定得读流啊, 所以当我获取到流的时候, 流已经被处理掉了, 所以我获取不到原始的请求正文了.
为了证明猜想, 下载Tomcat7源码看了下,发现果然是这样的 (org.apache.catalina.connector.Request.parseParameters()), 如图所示:
但是, 这个方法只有在调用 request.getParam* 等方法的时候才会触发解析操作. 看我上面服务端代码截图,第一行就是读流操作, 并没有request.getParam* 等方法的调用
百思不得其姐姐姐姐姐姐姐姐姐姐姐姐姐姐姐姐姐姐姐姐姐姐姐姐姐姐姐姐姐姐姐姐姐姐姐姐..............................
于是祭出终极手段, 搭建tomcat源码工程, 具体步骤见: http://my.oschina.net/haogrgr/blog/294274
在解析方法打上断点, 目的是为了查看调用堆栈, 找到触发解析的点.
最后终于找到了.......
项目里面用了Spring mvc, 然后加上了org.springframework.web.filter.HiddenHttpMethodFilter这个过滤器
该过滤器是因为浏览器不支持HTTP的PUT, DELETE等方法, 于是Spirng想出来一种办法, 通过为表单添加一个隐藏域
类似于: <input type="hidden" name="_method" value="PUT">
然后对每个请求拦截: 然后通过request.getParam("_method")来决定是不是要对request进行wrapper,如果该参数不为空,就包装为HttpMethodRequestWrapper,重写getMethod方法
妈的,跑题了.......
回到主题, 就是这个Filter调用了reqeuest.getParam()方法,而且 Content-Type为:application/x-www-form-urlencoded 所以触发了Tomcat对请求正文流的解析,导致我后面获取不到正文.
于是怎么解决呢? 最简单的方法, 项目中没有用到除GET和POST外的其他HTTP方法, so 去掉这个Filter , 啊,这个世界清静了................
但是, 如果我项目硬是要用这个Filter呢, 怎 末 办 ...........
蛋疼的解决办法来了:
写个Filter,放在web.xml的最前面(第一个), 然后在里面讲流的内容读完放到byte[]数组中缓存起来.....(可以缓存起来放入RequestWrapper对象中)
然后该Filter只拦截需要获取请求正文的url, 否则,其他Servlet将无法从request.getParam中获取参数......
你说什么, 你又要获取请求正文,又要调用request.getParam方法获取参数, 行, 将RequestWrapper对象的getParam等方法重写,自己按标准解析Post正文....
其实: 最好的解决办法, 是让客户端按标准来, 将请求正文类型改成 text/xml ,
但是, 你懂的~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
对方不按套路来, 一般人根本就把持不住啊~~~~~~~~~~~~~~~~~~~~~~~~~~~~