Shiro导致request.getInputStream()无法获取数据

来源:互联网 发布:淘宝袜子利润 编辑:程序博客网 时间:2024/06/05 11:31

之前参照:http://blog.csdn.net/kimmking/article/details/17505637

遇到的情况情况很相似

通过核心HttpURLConnection连接当前新开发的医疗系统,由于当前conn方法已经连接过其他旧系统,没有问题;

当连接此系统时发现问题,新系统中用request.getInputStream()接受数据流都是NULL

之前考虑到是由于Shiro或者什么之类的拦截导致;

幸好找到这篇文章,可以解决




今天发现一个很奇怪的问题,我们系统里用REST方式做前后端的访问,具体就是所有的请求都是POST,URL对应处理的action,HTTP body里的json是请求参数;后端程序里从Request.getReader拿到json参数,然后调用相应的action来处理。有一个登陆接口,在页面ajax和Android里请求是正常的,但是在iphone里请求出错。调试了下,发现request.getReader拿不到数据。

         通过tcpmon代理查看HTTP请求报文,对比下正确和错误的REST请求,感觉最大的问题可能是出现在Content-type上,进而发现application/x-www-form-urlencoded时,会出现这个问题,但是text/html,text/xml等格式都没有问题。这就能确定是Content-Type引起的了。

         为什么Content-Type会引起这个问题呢?

         我们知道request.getInputStream\getReader,都只能调用一次,调用过了,buffer里的数据就没有了。而request.getParameterXX方法也可能会解析buffer,如果这个调用过了,再调用getReader也会没有数据了。难道Content-Type不同的时候导致调用了这个?

         调试下,追了追shiro和tomcat的代码,发现果然如此。

请求进来先进过shiro的filter,filter里试图拿到当前subject,先从cookie试着拿sessionId,不行就从URL中试着拿sessionId,还没有的话就从request.getParameter里获取sessionId,这里调用到了tomcat的request.getParameter实现:如果Content-Type是multipart/form-data或者application/x-www-form-urlencoded,则直接解析http body……问题就出现了。

         简单的说就是,如果请求是application/x-www-form-urlencoded格式的话,shiro的filter在我们的servlet或action处理之前,就可能直接把request的body给读取并清空了。

通过这个实现我们也可以看到:除了这两个Content-Type之外的格式都不会有问题,登陆后sessionId放到cookie里了也不会有问题。

按理讲,我们用json应该手动设置Content-Type:application/json;因为application/x-www-form-urlencoded就是为了在body里使用类似QueryString的key-value格式。所以写代码的时候要注意了,如果某些HTTP库的实现里,默认POST是form格式的,如果你要自己处理HTTP body就需要手工的设置自己想要的Content-Type了。

         知道怎么回事了,就很好处理了。在xcode里,将Content-Type改成text/html或application/json即可。

         进一步的来看,shiro处理考虑到sessionId在cookie和url里,还考虑到一种情况:session藏在页面form的hidden里,通过form的post方式,把key-value作为http body来post到服务器端,shiro可能通过解析httpbody拿到sessionId,这个对session来说用处不大,因为我们一般都放到cookie或url的jsessionId里,但是对于某些需要自己处理http body的场景,shiro的filter显然破坏掉了后续对body的request.getReader读取。


阅读全文
0 0