4

这是我的 AJAX 函数:

/**
 * Send an AJAX request
 *
 * @param url      The URL to call (located in the /ajax/ directory)
 * @param data     The data to send (will be serialised with JSON)
 * @param callback The function to call with the response text
 * @param silent   If true, doesn't show errors to the user
 * @param loader   The element containing "Loading... Please wait"
 */
AJAX = function(url,data,callback,silent,loader) {
    var a,
        attempt = 0,
        rsc = function() {
            if( a.readyState == 4) {
                if( a.status != 200) {
                    if( a.status > 999) { // IE sometimes throws 12152
                        attempt++;
                        if( attempt < 5)
                            send();
                        else if( !silent) {
                            alert("HTTP Error "+a.status+" "+a.statusText+"<br />Failed to access "+url);
                        }
                    }
                    else if(!silent) {
                        alert("HTTP Error "+a.status+" "+a.statusText+"\nFailed to access "+url);
                    }
                }
                else {
                    callback(JSON.parse(a.responseText));
                }
            }
        },
        to = function() {
            a.abort();
            attempt++;
            if( attempt < 5)
                send();
            else if( !silent) {
                alert("Request Timeout\nFailed to access "+url);
            }
        };
    data = JSON.stringify(data);
    var send = function() {
        if( loader && attempt != 0) {
            loader.children[0].firstChild.nodeValue = "Error... retrying...";
            loader.children[1].firstChild.nodeValue = "Attempt "+(attempt+1)+" of 5";
        }
        a = new XMLHttpRequest();
        a.open("POST","/ajax/"+url,true);
        a.onreadystatechange = rsc;
        a.timeout = 5000;
        a.ontimeout = to;
        a.setRequestHeader("Content-Type","application/json");
        a.send(data);
    };
    send();
};

一般的想法是最多尝试请求五次。有时 IE 会因异常 HTTP 错误 (12xxx) 而失败,有时服务器可能无法响应。

我遇到的问题是abort()呼叫似乎没有中止连接。为了测试,我做了一个简单的 PHP 脚本:

<?php
    sleep(60);
    touch("test/".uniqid());
    die("Request completed.");
?>

touch()调用使用当前创建一个文件uniqid()- 通过查看修改时间,我可以看到sleep(60)结束的时间。

预期行为:

请求发送
5 秒后,文本变为“Error... Retying... Attempt 2/5”
重复上述操作直到 Attempt 5/5,然后失败。
对 PHP 文件的五次调用被中止,要么在“test”文件夹中有五个文件,间隔 5 秒,要么没有,因为 ignore_user_abort 已关闭。

观察到的行为(在 IE9 中):

请求已发送
尝试文本出现并按原样更改
五次尝试后,显示错误消息
我无法加载任何页面整整五分钟。
在服务器上,有五个文件间隔一分钟

我不知道该怎么做,因为在服务器端请求 3、4 和 5 是在浏览器上显示“超时”错误消息几分钟后发送的。

如果有任何区别,则进行 AJAX 调用的页面位于 iframe 中。重新加载 iframe(使用iframe.contentWindow.location.reload()并不能解决问题,它仍然等待这五个请求通过。

为什么会这样?我该如何解决?

编辑:我已经使用开发工具再次运行测试来监控网络活动。结果是:

URL          Method   Result     Type   Received  Taken   Initiator
/ajax/testto          (Aborted)              0 B  < 1 ms (Pending...)
/ajax/testto          (Aborted)              0 B  125 ms (Pending...)
/ajax/testto          (Aborted)              0 B  125 ms (Pending...)
/ajax/testto          (Aborted)              0 B  125 ms (Pending...)
/ajax/testto          (Aborted)              0 B  124 ms (Pending...)
4

4 回答 4

4

问题似乎是这样的,timeout并且ontimeout还不是某些实现的一部分:

var hasTimeout = 'timeout' in new XMLHttpRequest(); // false

至少,它不在 Chrome 16 或 Firefox 7 中。而且,这应该返回true给定的要求:

timeout属性必须返回其值。最初,它的值必须为零。

自2010 年 9 月 7 日以来,两者都成为XHR 2 规范的一部分。但是,由于“第 2 级”规范自2008 年 2 月 25 日以来一直存在并且仍然是“工作草案”,因此并不能真正保证任何实现都会与该规范保持同步。


如果没有您可用的那些,您可以尝试使用onabortand setTimeout(如您在评论中所述):

// snip

to = function() {
    attempt++;
    if( attempt < 5)
        send();
    else if( !silent) {
        console.log("Request Timeout\nFailed to access "+url);
    }
};

// snip

var send = function() {
    if( loader && attempt != 0) {
        loader.children[0].firstChild.nodeValue = "Error... retrying...";
        loader.children[1].firstChild.nodeValue = "Attempt "+(attempt+1)+" of 5";
    }
    a = new XMLHttpRequest();
    a.open("POST","/ajax/"+url,true);
    a.onreadystatechange = rsc;
    setTimeout(function () {     /* vs. a.timeout */
        if (a.readyState < 4) {
            a.abort();
        }
    }, 5000);
    a.onabort = to;              /* vs. a.ontimeout */
    a.setRequestHeader("Content-Type","application/json");
    a.send(data);
    console.log('HTTP Requesting: %s', url);
};

// snip

示例: http: //jsfiddle.net/AmQGM/2/ -?delay=2应该完成,而?delay=105 次尝试到期。

于 2012-01-25T00:08:54.650 回答
0

在中止请求之前,请尝试设置

a.onreadystatechange = function() {};

之后,还添加一个关于调用 abort 的检查:

if( a.readyState > 0 && a.readyState < 4 ) {
    a.abort();
}
于 2012-01-27T17:23:16.217 回答
0

运行您的代码时,我收到错误 c00c023f。当我用谷歌搜索它时,它想出了这个答案:

http://www.enkeladress.com/article.php/internetexplorer9jscripterror

这听起来与您正在经历的非常相似。

这是一个具有相同问题的 SO question,有一个解决方案(也基于上面的链接,但有附加信息):IE 9 Javascript error c00c023f

于 2012-02-02T06:14:56.813 回答
0

我有同样的问题,原来是 PHP 会话的问题。如果会话打开,则来自同一会话的所有其他请求都必须等待。

<?php
    session_write_close();
    sleep(60);
    touch("test/".uniqid());
    die("Request completed.");
?>

当然,如果您还没有开始会话,这对您没有帮助:)

于 2012-09-30T14:38:14.917 回答