重试其中有连接到其推迟回调一个jquery ajax请求 [英] Retry a jquery ajax request which has callbacks attached to its deferred

查看:162
本文介绍了重试其中有连接到其推迟回调一个jquery ajax请求的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图实施失败的原因,暂时重试Ajax请求的系统。就我而言,这是关于失败,401状态code,因为会话已过期,要求刷新web服务复兴在会议结束后重试请求。

I'm trying to implement a system of retrying ajax requests that fail for a temporary reason. In my case, it is about retrying requests that failed with a 401 status code because the session has expired, after calling a refresh webservice that revives the session.

问题是,完成回调不叫上一个成功的重试,不同的是成功的AJAX选项回调时被调用。我做了下面一个简单的例子:

The problem is that the "done" callbacks are not called on a successful retry, unlike the "success" ajax option callback that is called. I've made up a simple example below:

$.ajaxSetup({statusCode: {
    404: function() {
        this.url = '/existent_url';
        $.ajax(this);
    }
}});

$.ajax({
    url: '/inexistent_url',
    success: function() { alert('success'); }
})
.done(function() {
    alert('done');
});

有没有办法来一直呼吁一个成功的重试完成样式的回调?我知道延期不能'解决'后,这是'拒绝',是有可能prevent拒绝?或者,也许复制原始推迟到一个新的doneList推迟?我的想法:)

Is there a way to have done-style callbacks called on a successful retry? I know a deferred can't be 'resolved' after it was 'rejected', is it possible to prevent the reject? Or maybe copy the doneList of the original deferred to a new deferred? I'm out of ideas:)

下面一个更现实的例子,在这里我想排队的所有401-被拒绝的请求,并成功调用/刷新后重试它们。

A more realistic example below, where I'm trying to queue up all 401-rejected requests, and retry them after a successful call to /refresh.

var refreshRequest = null,
    waitingRequests = null;

var expiredTokenHandler = function(xhr, textStatus, errorThrown) {

    //only the first rejected request will fire up the /refresh call
    if(!refreshRequest) {
        waitingRequests = $.Deferred();
        refreshRequest = $.ajax({
            url: '/refresh',
            success: function(data) {
                // session refreshed, good
                refreshRequest = null;
                waitingRequests.resolve();
            },
            error: function(data) {
                // session can't be saved
                waitingRequests.reject();
                alert('Your session has expired. Sorry.');
            }
       });
    }

    // put the current request into the waiting queue
    (function(request) {
        waitingRequests.done(function() {
            // retry the request
            $.ajax(request);
        });
    })(this);
}

$.ajaxSetup({statusCode: {
    401: expiredTokenHandler
}});

该机制的工作,401-失败的请求被解雇了第二次,但问题是他们'做'回调不会被调用,所以应用程序摊位。

The mechanism works, the 401-failed requests get fired a second time, the problem is their 'done' callbacks do not get called, so the applications stalls.

推荐答案

您可以使用 jQuery.ajax prefilter 包裹jqXHR在另一个延迟对象

我作出一个例子的jsfiddle ,显示它的工作,并试图以适应你的一些code处理401到这个版本:

I made an example on jsFiddle that shows it working, and tried to adapt some of your code to handle the 401 into this version:

$.ajaxPrefilter(function(opts, originalOpts, jqXHR) {
    // you could pass this option in on a "retry" so that it doesn't
    // get all recursive on you.
    if (opts.refreshRequest) {
        return;
    }

    // our own deferred object to handle done/fail callbacks
    var dfd = $.Deferred();

    // if the request works, return normally
    jqXHR.done(dfd.resolve);

    // if the request fails, do something else
    // yet still resolve
    jqXHR.fail(function() {
        var args = Array.prototype.slice.call(arguments);
        if (jqXHR.status === 401) {
            $.ajax({
                url: '/refresh',
                refreshRequest: true,
                error: function() {
                    // session can't be saved
                    alert('Your session has expired. Sorry.');
                    // reject with the original 401 data
                    dfd.rejectWith(jqXHR, args);
                },
                success: function() {
                    // retry with a copied originalOpts with refreshRequest.
                    var newOpts = $.extend({}, originalOpts, {
                        refreshRequest: true
                    });
                    // pass this one on to our deferred pass or fail.
                    $.ajax(newOpts).then(dfd.resolve, dfd.reject);
                }
            });

        } else {
            dfd.rejectWith(jqXHR, args);
        }
    });

    // NOW override the jqXHR's promise functions with our deferred
    return dfd.promise(jqXHR);
});

这工作,因为 deferred.promise(对象) 实际上将覆盖所有的在jqXHR的承诺法。

This works because deferred.promise(object) will actually overwrite all of the "promise methods" on the jqXHR.

注意::要大家有没有发现,如果要连接回调与成功:错误:在阿贾克斯的选项,这个片段将不可以工作,你所期望的方式。它假定只有回调是使用 .done(回调) .fail(回调)方法附加的那些的jqXHR。

NOTE: To anyone else finding this, if you are attaching callbacks with success: and error: in the ajax options, this snippet will not work the way you expect. It assumes that the only callbacks are the ones attached using the .done(callback) and .fail(callback) methods of the jqXHR.

这篇关于重试其中有连接到其推迟回调一个jquery ajax请求的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆