jquery - 重试 jquery ajax 请求,该请求已附加到其延迟的回调

标签 jquery ajax jquery-deferred

我正在尝试实现一个重试因临时原因失败的 ajax 请求的系统。就我而言,它是关于在调用恢复 session 的刷新 Web 服务后重试因 session 已过期而失败并显示 401 状态代码的请求。

问题在于,与调用的“成功”ajax 选项回调不同,在成功重试时不会调用“完成”回调。我在下面编写了一个简单的示例:

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

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

有没有办法在成功重试时调用完成样式的回调?我知道延迟被“拒绝”后无法“解决”,是否可以防止拒绝?或者也许将原始延迟的 didList 复制到新的延迟?我没有主意了:)

下面是一个更实际的示例,我尝试将所有 401 拒绝的请求排队,并在成功调用/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 失败的请求会再次被触发,问题是它们的“完成”回调不会被调用,因此应用程序会停止。

最佳答案

您可以使用jQuery.ajaxPrefilter将 jqXHR 包装在另一个 deferred object 中.

我在jsFiddle上做了一个例子这表明它正在工作,并尝试调整一些代码以处理 401 到此版本中:

$.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(object)实际上会覆盖 jqXHR 上的所有“promise 方法”。

注意:对于发现此内容的其他人,如果您在 ajax 选项中附加带有 success:error: 的回调,则此代码段将按照您期望的方式工作。它假设唯一的回调是使用 jqXHR 的 .done(callback).fail(callback) 方法附加的回调。

关于jquery - 重试 jquery ajax 请求,该请求已附加到其延迟的回调,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11793430/

相关文章:

jquery - 始终处于事件状态的 Bootstrap 下拉菜单

javascript - 鼠标滚动 - 对齐 div

javascript - 请求刷新页面

javascript - 如何在没有 "Requested unknown parameter"错误的情况下动态添加行

javascript函数等待另一个函数完成

jquery - 延迟和 Ajax

javascript - 可重用的 jQuery 函数

php - 将 Mustache.js 与 Mustache.php 结合使用

javascript - 使用 ajax 传递 # 值不起作用

jquery - 将函数的执行推迟到其他事件发生之后