5

我使用以下代码重试返回 HTTP 502、503 或 504 的操作:

/**
 * @function RetryDelayFunction
 * Returns the amount of time to wait after a failure.
 *
 * @param {Number} retries the number of times the operation has been retried
 * @return {Number} the number of milliseconds to wait before retrying the operation
 */

/**
 * @typedef {Object} RetryAjaxOptions
 *
 * @property {Number} retries the number of times to retry a failed operation
 * @param {RetryDelayFunction} delayFunction maps a failure count to a delay in milliseconds
 * @param {Array} errorCodes the HTTP response codes that should trigger a retry
 */

/**
 * Retries HTTP requests using an exponential back-off in case of HTTP 502, 503, 504. Based on
 * https://github.com/execjosh/jquery-ajax-retry and http://javadoc.google-http-java-client.googlecode.com/hg/1.15.0-rc/com/google/api/client/util/ExponentialBackOff.html
 *
 * The $.ajax() settings object must contain a {@code retry} key to enable this functionality.
 * This object is of type {@link RetryAjaxOptions} and may be used to override the default behavior.
 */
function installAjaxRetries()
{
    "use strict";
    /**
     * Do nothing.
     */
    var noOpFunction = function()
    {
    };

    var delayInitialIntervalMs = 250;
    var delayIntervalMultiplier = 1.5;
    var delayRandomizationFactor = 0.5;

    /**
     * @function RetryDelayFunction
     */
    var defaultDelayFunction = function(retries)
    {
        var retryInterval = delayInitialIntervalMs * Math.pow(delayIntervalMultiplier, retries);
        var delta = retryInterval * delayRandomizationFactor;
        var min = retryInterval - delta;
        var max = retryInterval + delta;
        return (Math.random() * (max - min + 1)) + min;
    };

    var MIN_RETRIES = 1;
    var DEFAULT_RETRIES = 3;
    var DEFAULT_ERROR_CODES = [502, 503, 504];

    var DEFAULT_OPTIONS =
        {
            retries: DEFAULT_RETRIES,
            delayFunction: defaultDelayFunction,
            errorCodes: DEFAULT_ERROR_CODES
        };
    var originalAjaxFunction = $.ajax;
    var ajaxWithRetry = function(settings)
    {
        settings = $.extend(true, {}, $.ajaxSettings, settings);
        if (!settings.retry)
            return originalAjaxFunction(settings);

        var retries = 0;
        var options = $.extend(true, {}, $.ajaxRetrySettings, settings.retry);
        var originalErrorFunction = settings.error || noOpFunction;
        var originalCompleteFunction = settings.complete || noOpFunction;

        // Clamp options
        options.retries = Math.max(MIN_RETRIES, options.retries);
        options.delayFunction = options.delayFunction || defaultDelayFunction;

        // Override error function
        settings.error = function(xhr, textStatus, errorThrown)
        {
            if ($.inArray(xhr.status, options.errorCodes) < 0 || retries >= options.retries)
            {
                // Give up and call the original error() function
                originalErrorFunction.call(this, xhr, textStatus, errorThrown);
                return;
            }
            // The complete() handler will retry the operation
        };

        // Override complete function
        settings.complete = function(xhr, textStatus)
        {
            if ($.inArray(xhr.status, options.errorCodes) < 0 || retries >= options.retries)
            {
                // Give up and call the original complete() function
                originalCompleteFunction.call(this, xhr, textStatus);
                return;
            }
            var delayMs = options.delayFunction(retries);
            ++retries;
            window.setTimeout(function()
            {
                originalAjaxFunction(settings);
            }, delayMs);
        };

        originalAjaxFunction(settings);
        return settings.xhr;
    };

    var ajaxRetrySetup = function(options)
    {
        DEFAULT_OPTIONS = $.extend(true, DEFAULT_OPTIONS, options);
        $.ajaxRetrySettings = DEFAULT_OPTIONS;
        return DEFAULT_OPTIONS;
    };

    $.ajaxRetrySettings = DEFAULT_OPTIONS;
    $.ajaxRetrySetup = ajaxRetrySetup;
    $.ajax = ajaxWithRetry;
}
installAjaxRetries();

自从我开始使用这段代码以来,一些 AJAX 调用开始返回 HTTP 200 和一个空的 responseText。奇怪的是,第一个请求失败了(实际上没有重试),只需注释掉覆盖的代码即可settings.complete解决问题。我正在使用 Chrome 29.0.1547.57 m。

为什么覆盖settings.complete会导致这个问题?

更新:我控制服务器,所以我知道它永远不会返回带有空响应的 HTTP 200。

UPDATE2:我无法再重现该问题,我不记得我做了什么来解决它。如果我不能在接下来的几个月内复制它,我计划关闭它。

4

1 回答 1

1

可能是您正在尝试跨域 server.set 响应标头以允许访问源

于 2013-09-06T14:30:06.203 回答