jQuery JSONP Ajax请求执行成功却触发错误回调问题排查
原因分析
当你在jQuery的$.ajax中显式指定jsonpCallback: "myFunction"时,jQuery的预期是由它自身创建并管理这个回调函数,而非你提前在全局作用域定义同名函数。
如果你自己提前定义了myFunction,服务端返回的myFunction({"key": "value"});会直接执行你写的函数,但这个函数并没有绑定jQuery内部的请求成功标记逻辑。jQuery会在请求发起后启动超时计时器,因为检测不到它创建的回调函数被调用,最终判定请求失败,进入错误回调——哪怕你的myFunction实际已经执行。
解决方法
方法1:移除jsonpCallback参数(推荐)
让jQuery自动生成随机的临时回调函数名,这是JSONP的标准使用方式:
$.ajax({ url: "http://localhost:12345", type: "GET", dataType: "jsonp", cache: false, success: function (data) { console.log('success'); console.log(data); // 这里可以拿到{"key": "value"} }, error: function (jqxhrInternal, message, errorThrown) { console.log(JSON.stringify(jqxhrInternal)); console.log('message: ' + message); console.log('errorThrown: ' + errorThrown); } });
此时jQuery会自动在请求URL后追加类似?callback=jQuery3610xxxx的参数,你需要让服务端读取URL中的callback参数值,返回对应函数名的调用(比如jQuery3610xxxx({"key": "value"});)。
方法2:保留jsonpCallback但不手动定义同名函数
如果你必须固定回调函数名,不要自己提前定义myFunction,让jQuery创建这个函数:
// 不要提前定义myFunction $.ajax({ url: "http://localhost:12345", type: "GET", dataType: "jsonp", jsonpCallback: "myFunction", cache: false, success: function (data) { console.log('success'); console.log(data); }, error: function (jqxhrInternal, message, errorThrown) { console.log(JSON.stringify(jqxhrInternal)); console.log('message: ' + message); console.log('errorThrown: ' + errorThrown); } });
jQuery会自动创建全局的myFunction,函数内部会触发success回调并标记请求成功,执行后会自动销毁这个函数。服务端依然返回myFunction({"key": "value"});即可。
方法3:手动绑定jQuery的成功逻辑(不推荐)
如果一定要自己定义myFunction,需要在函数内部调用jQuery的内部处理逻辑。你可以先获取jQuery生成的回调函数引用,再在自己的函数中调用它:
// 先发起请求前,让jQuery创建回调函数 var originalCallback; $.ajax({ url: "http://localhost:12345", type: "GET", dataType: "jsonp", jsonpCallback: "myFunction", cache: false, beforeSend: function() { // 保存jQuery创建的myFunction originalCallback = window.myFunction; // 替换成自己的函数 window.myFunction = function(data) { console.log('自定义myFunction执行'); // 调用原始的jQuery回调,触发success originalCallback(data); }; }, success: function (data) { console.log('success'); console.log(data); }, error: function (jqxhrInternal, message, errorThrown) { console.log(JSON.stringify(jqxhrInternal)); console.log('message: ' + message); console.log('errorThrown: ' + errorThrown); } });
这种方式比较繁琐,仅在特殊场景下使用。
内容的提问来源于stack exchange,提问作者Shadow

