我使用以下代码重试返回 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:我无法再重现该问题,我不记得我做了什么来解决它。如果我不能在接下来的几个月内复制它,我计划关闭它。