ECSHOP的后台每次删除一个商品都要报下面的错误
Uncaught transport.js/parseResult() error: can't parse to JSON.
错误的原因是ajax的返回值是空字符串, 而ajax中规定的格式是JSON, 返回之后要对字符串进行parseJSON, 空字符串被认为不是合法的JSON字符串. 看看代码就知道了:
try { if (/^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/.test(this)) { var j = eval('(' + this + ')'); if (typeof filter === 'function') { function walk(k, v) { if (v && typeof v === 'object') { for (var i in v) { if (v.hasOwnProperty(i)) { v[i] = walk(i, v[i]); } } } return filter(k, v); } j = walk('', j); } return j; } } catch (e) { // Fall through if the regexp test fails. } throw new SyntaxError("parseJSON"); };
正则表达式会是false, 从而抛出异常. 这里主要的原因是为什么AJAX返回空字符串. 比如一个典型的ajax url:
"http://127.0.0.144/shop/admin/goods.php?is_ajax=1&act=remove&id=32&cat_id=0&intro_type=&is_promote=0&stock_warning=0&brand_id=0&keyword=&suppliers_id=&is_on_sale=&sort_by=goods_id&sort_order=DESC&extension_code=&is_delete=0&real_goods=1&record_count=1&page_size=15&page=1&page_count=1&start=0&1346143445423423"
这个url会执行一个删除商品的动作然后执行一个header location进行重定向, 重定向的url会返回刷新的商品列表的JSON表示, 返回到ajax中, 解析之后写入到HTML页面上. 这原本是一个普通的ajax删除然后刷新, 而且在IE下面工作很正常. 而Chrome里面行不通. 搜索了一下, 这可能是一个问题, 不知道算不算bug, 在Chrome 18里面就提出来了, 例如http://code.google.com/p/chromium/issues/detail?id=121614 , 我用的是19, 显然问题还是没有修复.
先讲一下原理, header Location会发送一个302的HTTP响应, 按照WEB标准, 浏览器应该透明的执行重定向, 应用程序应该可以对重定向的过程毫不知情, 也不应该收到302这个状态, 例如请求a.php, 但是得到的是b.php的输出, 如果b.php正常执行那么ajax应该直接得到一个200的响应. 那么Chrome是如何处理这个问题的? 在控制台中打开Network面板得到下面的图:
Chrome收到了302, 但是每一个302都是canceled. 显然这是浏览器内部的行为, 与脚本无关. 然后我用了jQuery来测试了一下
a.php<script>$(document).ready(function(){ $('#abutton').click(function(){ $.ajax({ type: 'GET', url: 'b.php', data: { usertheme : 'sss' }, dataType: 'text', success : function(xml) { var a = 'jjiji';alert('success' + xml); }, error : function(a,b,c) { var b = 'sjfiwf'; alert('error'); }, complete : function() { alert('complete'); } }); });});</script><body><a href="javascript:;" id="abutton">ajax请求</a></body>b.php<?php//echo 'ajfeiofjei;'; exit;header("Location: c.php"); exit;?>c.php<?phpecho 'output form c.hphp'; exit;?>
结果$.ajax的error函数被调用.
Chrome的控制台有个"Copy as HAR"的功能, 是请求响应的详细信息, 从中可以发现一点蛛丝马迹:
"request": { "method": "GET", "url": "http://127.0.0.144/shop/admin/goods.php?is_ajax=1&act=remove&id=32&cat_id=0&intro_type=&is_promote=0&stock_warning=0&brand_id=0&keyword=&suppliers_id=&is_on_sale=&sort_by=goods_id&sort_order=DESC&extension_code=&is_delete=0&real_goods=1&record_count=1&page_size=15&page=1&page_count=1&start=0&1346143445423423", "httpVersion": "HTTP/1.1", "headers": [ { "name": "Accept-Encoding", "value": "gzip,deflate,sdch" }, { "name": "Accept-Language", "value": "zh-CN,zh;q=0.8" }, ], "cookies": [ { "name": "ECS_LastCheckOrder", "value": "Tue%2C%2028%20Aug%202012%2008%3A43%3A40%20GMT", "expires": null, "httpOnly": false, "secure": false }, ], "headersSize": 2775, "bodySize": 0 }, "response": { "status": 302, "statusText": "Found", "httpVersion": "HTTP/1.1", "headers": [ { "name": "Server", "value": "Apache/2.0.63 (Win32) PHP/5.2.10" }, { "name": "Location", "value": "goods.php?act=query&is_ajax=1&&id=32&cat_id=0&intro_type=&is_promote=0&stock_warning=0&brand_id=0&keyword=&suppliers_id=&is_on_sale=&sort_by=goods_id&sort_order=DESC&extension_code=&is_delete=0&real_goods=1&record_count=1&page_size=15&page=1&page_count=1&start=0&1346143445423423" }, ], "cookies": [], "content": { "size": 0, "mimeType": "text/html", "compression": 0 }, "redirectURL": "goods.php?act=query&is_ajax=1&&id=32&cat_id=0&intro_type=&is_promote=0&stock_warning=0&brand_id=0&keyword=&suppliers_id=&is_on_sale=&sort_by=goods_id&sort_order=DESC&extension_code=&is_delete=0&real_goods=1&record_count=1&page_size=15&page=1&page_count=1&start=0&1346143445423423", "headersSize": 712, "bodySize": 0 }, "cache": {}, "pageref": "page_12" }, { "request": { "method": "GET", "url": "http://127.0.0.144/shop/admin/goods.php?act=query&is_ajax=1&&id=32&cat_id=0&intro_type=&is_promote=0&stock_warning=0&brand_id=0&keyword=&suppliers_id=&is_on_sale=&sort_by=goods_id&sort_order=DESC&extension_code=&is_delete=0&real_goods=1&record_count=1&page_size=15&page=1&page_count=1&start=0&1346143445423423", "httpVersion": "HTTP/1.1", "headers": [ { "name": "User-Agent", "value": "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.1 Safari/536.5" }, { "name": "Referer", "value": "http://127.0.0.144/shop/admin/goods.php?act=list" } ], ], "cookies": [], "headersSize": 495, "bodySize": 0 }, "response": { "status": 0, "statusText": "", "httpVersion": "HTTP/1.1", "headers": [], "cookies": [], "content": { "size": 0, "compression": 0 }, "redirectURL": "", "headersSize": 13, "bodySize": 0 },
里面记录了请求响应的流程, 这里面第一个url请求, 响应是一个302, 之后根据302响应头中的Location字段构造了一个重定向的请求, 得到一个状态值为0的响应, 这个响应就是在ajax返回的时候所看到的那个, 符合透明重定向的原则. 看起来似乎有一个GET请求是指向重定向的url的, 而且还有一个response, 这个response的状态值是0. 那么这个GET请求到底有没有发出去, 答案是没有. Chrome只是构造了这个请求, 然后因为某种原因canceled, 之后又构造了一个response, 一个没有任何内容的response, 返回给ajax.
仍然没有搞清楚的是Chrome根据什么条件决定cancel这个重定向请求 ?
有一点要提到的是, 有些帖子里面说判断status的值, 如果是302就获取其header中的Location, 然后赋值给document.location. 这是行不通的, 因为302状态码是不会在脚本中见到的, 脚本要么得到一个错误或者200或者状态0 . StackOverflow上面有好多这样的例子, 容易误解.
0 0