DWR框架 获取请求数据问题
DWR框架可以直接js里面调用后端的Java类方法,看起来似乎非常cool但是其中隐藏了各种坑。dwr的实现方式是一个普通的servlet,拦截所有dwr请求。不同于其他框架的是dwr在参数传递的时候是个奇葩。估计很多人在用Struts2+dwr的时候经常会遇到dwr弹框:No data received from server。这个问题主要就是因为Struts2的Filter会调用apache-commons-fileupload的isMultipartContent()判断是否是文件上传请求。问题应该就出在这里,在commons-fileupload解析文件请求的时候会打开一个输入流,这个流一旦打开之后后面的dwr就没办法获取了。
DWR请求:
POST /Struts/dwr/call/plaincall/Test.getData.dwr HTTP/1.1 Host: localhost:8080 Connection: keep-alive Content-Length: 215 Origin: http://localhost:8080 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.152 Safari/537.36 Content-Type: text/plain Accept: */* Referer: http://localhost:8080/Struts/dwr/test/Test Accept-Encoding: gzip,deflate,sdch Accept-Language: zh-CN,zh;q=0.8,en;q=0.6 Cookie: JSESSIONID=1D13ABFF70F33FD4D31CB9A1F3538126; DWRSESSIONID=tFvo*cCk*4*c1gNuMNg0NOrSzjk; JSESSIONID=41920E755C29CEC7DE0E53C914FED043 callCount=1 windowName= c0-scriptName=Test c0-methodName=getData c0-id=0 c0-param0=string:123 batchId=13 instanceId=0 page=%2FStruts%2Fdwr%2Ftest%2FTest scriptSessionId=tFvo*cCk*4*c1gNuMNg0NOrSzjk/8$pVzjk-VV3A8hwlt
仔细一看你发发现dwr的请求挺坑爹的,以为普通的POST请求参数应该是这样的:"id=1&pass=123456...."。而dwr的请求参数格式却是:callCount=1windowName=c0-scriptName=Testc0-methodName=getDatac0-id=0c0-param0=string:123batchId=3instanceId=0page=%2FStruts%2Fdwr%2Ftest%2FTestscriptSessionId=d2JCS0HfiZLKSpXm99aFeCy6Ajk/7Ay6Ajk-QphNGIXOi。这参数传到后端Server根本就没办法封装到请求里面去。这对依赖server解析后的Parameter的业务来说无疑是个坑,因为只能从ServletInputStream中获取dwr的请求参数...
org.directwebremoting.dwrp.Batch.java的parseBasicPost方法:
if (charEncoding != null){ in = new BufferedReader(new InputStreamReader(req.getInputStream(), charEncoding)); }else{ in = new BufferedReader(new InputStreamReader(req.getInputStream())); } while (true){ String line = in.readLine(); ......省略...... }
既然知道了差异解决办法自然会很简单了。在处理ServletInputStream之前先复制一份流,把副本传递给应用就行了。而对于Struts2最简单的解决办法就是不拦截dwr的请求就ok了。