最近一个项目,客户端使用用jQuery编写ajax请求,服务端采用struts2框架。js发送请求和action处理请求过程中,遇到一个问题。刚开始觉得问题很诡异,仔细定位很久之后才发现问题,虽然问题解决了, 但更深层次的原因还不清楚,欢迎大牛们指导。
1.问题现象
- 客户端问题
通过IE9下的开发人员工具F12发现,浏览器的确是发送了post请求,但是该请求“结果”栏显示的是“已终止”,“发起程序”值 是“已挂起”。请求头、请求体、响应头、响应体都是空的。也就说浏览器发送了1个异常的请求。
- 服务端问题
Struts2的action能够接受到post的请求,但是获取不到请求参数的值。
2.相关JS代码
- function sendMessage()
- {
- $.post("indvAction!sendShortMsg.action", {
- "configType" : "1"
- });
- }
- //弹出确认对话框
- Nf.promptConfirm({
- message :”operation success”,
- width : 300,
- height : 150,
- handler : function(btn)
- {
- if (btn == "ok")
- {
- //向服务器发送ajax请求
- sendMessage()
- //关闭当前页面
- NfLayout.closeTab();
- }
- }
- });
function sendMessage() { $.post("indvAction!sendShortMsg.action", { "configType" : "1" }); } //弹出确认对话框 Nf.promptConfirm({ message :”operation success”, width : 300, height : 150, handler : function(btn) { if (btn == "ok") { //向服务器发送ajax请求 sendMessage() //关闭当前页面 NfLayout.closeTab(); } } });
3.定位过程
刚开始使用F12没有得到与定位问题有关的信息。后面使用httpWatch或burp suite进行http抓包,查看原始的http请求和响应报文。结果发现了问题。
1、浏览器发出的请求报文中,的确没有传递configType字段的值。请求报文如下:
- POST /mobile/jsp/indvconfig/indvAction!sendShortMsg.action HTTP/1.1
- x-requested-with: XMLHttpRequest
- Accept-Language: zh-CN,en;q=0.5
- Referer: https://*.*.*.*:17243/mobile/jsp/indvconfig/indv_config.jsp
- Accept: */*
- Content-Type: application/x-www-form-urlencoded
- Accept-Encoding: gzip, deflate
- User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)
- Host: 11.12.213.87:17243
- Content-Length: 0
- Connection: Keep-Alive
- Cache-Control: no-cache
- Cookie: JSESSIONID=62C9FF9CBC97731B120ABAC297C4E4C5
POST /mobile/jsp/indvconfig/indvAction!sendShortMsg.action HTTP/1.1 x-requested-with: XMLHttpRequest Accept-Language: zh-CN,en;q=0.5 Referer: https://*.*.*.*:17243/mobile/jsp/indvconfig/indv_config.jsp Accept: */* Content-Type: application/x-www-form-urlencoded Accept-Encoding: gzip, deflate User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0) Host: 11.12.213.87:17243 Content-Length: 0 Connection: Keep-Alive Cache-Control: no-cache Cookie: JSESSIONID=62C9FF9CBC97731B120ABAC297C4E4C5
2、浏览器的确收到了服务器的响应报文。
- HTTP/1.1 200 OK
- Server: Apache-Coyote/1.1
- Content-Type: text/plain;charset=UTF-8
- Vary: Accept-Encoding
- Date: Fri, 22 Nov 2013 01:34:31 GMT
- Content-Length: 6
- this is my response!
HTTP/1.1 200 OK Server: Apache-Coyote/1.1 Content-Type: text/plain;charset=UTF-8 Vary: Accept-Encoding Date: Fri, 22 Nov 2013 01:34:31 GMT Content-Length: 6 this is my response!其实一切都很正常了,浏览器确实发送了HTTP请求,只不过是没有携带请求参数值,只不过是被IE9的展示方式欺骗了,所以刚开始定位很久都没有头绪。现在产生了如下问题:为什么浏览器发送了ajax请求,但是没有携带请求参数?为什么IE9显示请求是“已挂起”、“已终止”?
4.问题解决
去掉NfLayout.closeTab();这行代码就可以解决问题了。这是因为jquery的POST请求是异步的,当post请求还没有准备好数据的时候,这个时候执行了NfLayout.closeTab();当前页面关闭,导致了浏览器终止了http请求。这样的话就,相当于是请求被异常终止,于是IE9显示请求“已挂起”、“已终止”。具体深层次的原因不清楚,下面是个人一些猜想和解释:
1、 JS代码只有加载才会被执行,而触发js加载的正是html/jsp页面的显示。所以,我觉得Html/jsp就是js的执行环境。如果js还没有执行完,页面关闭的话,后续js代不会再执行。测试代码如下:
- <head>
- <script type='text/javascript'>
- function test()
- {
- alert(1111);
- window.opener = "";
- window.open("","_self");
- window.close();
- alert("我不会在执行了,因为页面已经关闭。");
- //setTimeout('callBack( )', 3000)
- }
- </script>
- </head>
- <body>
- <input id="button_-12你" type="button" value="testRight" onclick="test();">
- </body>
<head> <script type='text/javascript'> function test() { alert(1111); window.opener = ""; window.open("","_self"); window.close(); alert("我不会在执行了,因为页面已经关闭。"); //setTimeout('callBack( )', 3000) } </script> </head> <body> <input id="button_-12你" type="button" value="testRight" onclick="test();"> </body>个人感觉,可能是jquery拼post的请求体,会相对比较耗时,还没有执行完毕。此时页面关闭,JS终止了执行,浏览器发送了1个不完全的HTTP请求(没有附上请求体)。 这是个人的猜测,大家有自己见解的,欢迎指教。基于这个结论,我们将POST请求,改成Get请求,虽然IE9显示的还是请求终止,但是服务端能够收到请求的参数值了。