使用 jQuery 中止 JSONP ajax 请求

Posted

技术标签:

【中文标题】使用 jQuery 中止 JSONP ajax 请求【英文标题】:Abort JSONP ajax request with jQuery 【发布时间】:2011-09-22 06:50:04 【问题描述】:

我正在使用 JSONP ajax 调用从不同的域加载一些内容,如果用户在按钮上引起“鼠标悬停”,所有这些内容都会执行。

我可以将 $.ajax() 调用返回捕获为 xhr 对象,并在每次用户导致“鼠标悬停”时中止 ajax 请求。但是JSONP回调函数仍然被调用,这会导致错误,我认为这是因为xhr.abort()方法并没有阻止回调函数被调用。

我尝试使用 trycatch(e) 包围 $.ajax() 调用,但在调用 xhr.abort() 方法后,错误仍然存​​在。

有没有办法处理这个异常?

引发的异常是这样的(根据 Firebug): jQuery16102234208755205157_1308941669256 不是函数

而异常的内部结构是这样的: jQuery16102234208755205157_1308941669256(...我来自不同域的json数据...)

【问题讨论】:

Kill ajax requests using javascript using jquery.的可能重复 我想这不是那么重复,因为这个问题是关于在 JSONP ajax 请求上调用 jqxhr.abort() 方法之后防止异常,而不是关于如何停止请求本身。 这个问题的答案可以在重复问题***.com/questions/9533848/…找到 非常老的问题。今天偶然发现了同样的问题。我添加了我的贡献。我不知道我的答案是否值得被接受,但可以肯定的是,接受的答案不应该是当前(被否决的)答案 【参考方案1】:

基本的答案就是给定here:你不能真的abort() 一个JSONP 调用。所以真正的问题是,如何避免多余的回调调用和您看到的错误?

你不能在回调周围使用try...catch,因为它是异步的;您必须从 jQuery 的末尾捕获它,并且 jQuery 通常不处理回调引发的异常。 (我在我的书中讨论了这个问题,Async JavaScript。)您想要做的是为每个 Ajax 调用使用一个唯一标识符,并且在调用成功回调时,检查该标识符是否与您创建时的标识符相同通话。这是一个简单的实现:

var requestCount = 0;
$.ajax(url, 
  dataType: 'jsonp',
  requestCount: ++requestCount,
  success: function(response, code) 
    if (requestCount !== this.requestCount) return;
    // if we're still here, this is the latest request...
  
);

这里我利用了这样一个事实,即您传递给$.ajax 的任何内容都附加到在回调中用作this 的对象。

当然,如果 jQuery 让 abort() 为我们做这件事就好了。

【讨论】:

【参考方案2】:

不要中止请求

只需将$.ajax()返回的jqXHR对象存储在某处

theJqXHR = $.ajax(....

如果用户取消请求,则保存的对象为空

// user canceled
theJqXHR = null;

最后,当您收到响应(success 回调)时,回调会将响应的 jqXHR 对象与保存的对象进行比较。

function successCallback(data, textStatus, jqXHR )

    if( theJqXHR !== jqXHR )
    
        // user canceled; discard the response
        return;
    

    // process the response

没有 jQuery 错误。


一般建议不要依赖abort(),即使是常规的 ajax 请求。

    在任何情况下,您都不会在服务器上节省资源,因为您发送的请求将被处理并且无法停止。并且会有回应。

    一些(旧)浏览器无法正确处理abort()

只需“缓存”jqXHR 对象并自己处理CANCEL 场景。

【讨论】:

第三个参数 XHR 从不匹配 $.ajax 返回的对象 @JackCole 我试过了,实际上是的,确实如此。在控制台上试试这个:jqxhr1=$.ajax(url: "/", success: function(data,status,jqxhr2)alert(jqxhr1===jqxhr2);) 我得到的是true【参考方案3】:

jsonpString 覆盖 jsonp 请求中的回调函数名称。在“callback=?”中将使用该值代替“callback” URL 中查询字符串的一部分。

所以jsonp:'onJSONPLoad' 将导致'onJSONPLoad=?' 传递给服务器。从 jQuery 1.5 开始,将 jsonp 选项设置为 false 可防止 jQuery 将 ?callback 字符串添加到 URL 或尝试使用 =? 进行转换。在这种情况下,您还应该明确设置jsonpCallback 设置。例如, jsonp: false, jsonpCallback: "callbackName"

http://api.jquery.com/jQuery.ajax/

jQuery 添加?callback=jQuery17109492628197185695_1339420031913 并稍后将请求数据设置为此回调的参数,因此您将拥有:

jQuery17109492628197185695_1339420031913(
  "status": 200,
  "data": your json
)

为避免设置额外的参数来请求URL和调用回调,将此参数添加到ajax方法:jsonp:false,所以它看起来像:

$.ajax(
  ...
  jsonp:false,
  ...
);

【讨论】:

【参考方案4】:

Trevor Burnham 的回答非常好,但您应该只将请求与 XHR 参数进行比较,而不是跟踪请求计数,就像这样;

doRequest: function() 
    this._freeRequest();

    this._request = $.getJSON(url + params + '&callback=?', function(response, status, xhr) 
        if (this._request !== xhr) return; // aborted

        // success
    .bind(this)).done(this._freeRequest.bind(this));


_freeRequest: function() 
    if (this._request) 
        delete this._request;
    

在前一个请求完成之前再次调用doRequest_freeRequest 一次,将导致if (this._request !== xhr) 行变为真,从而导致所述请求的“中止”,因为this._request 将被删除或完全是另一个请求。

【讨论】:

【参考方案5】:

在 jQuery 1.5 中,所有 Ajax API 都有一个围绕原生 XHR 对象的包装器对象。看看:

http://api.jquery.com/jQuery.ajax/#jqXHR

 jqxhr.abort(); // should be what you're looking for

【讨论】:

这是我现在使用的。这将中止 ajax 请求。但是这个 ajax 请求使用 JSONP。在我使用“abort()”方法之后,调用了一个由 jQuery 内部生成的用于处理 JSONP 响应的 javascript 函数,但是 abort 方法似乎删除了该函数定义,或者什么,因为有一个我没有的异常能够应付。 您还有更多信息吗?现场示例,异常消息?

以上是关于使用 jQuery 中止 JSONP ajax 请求的主要内容,如果未能解决你的问题,请参考以下文章

JQuery+ajax+jsonp 跨域访问

使用 jQuery 中止 Ajax 请求

使用 jQuery deferred 中止 AJAX 请求链

jQuery ajax调接口时跨域

使用 jQuery 中止待处理/积压的 AJAX 请求

使用 JSONP 时如何捕获 jQuery $.getJSON(或数据类型设置为“jsonp”的 $.ajax)错误?