【问题标题】:xmlhttprequest timeout / abort not working as expected?xmlhttprequest 超时/中止没有按预期工作?
【发布时间】:2012-01-24 22:17:39
【问题描述】:

这是我的 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) 结束的时间。

预期行为:

请求已发送
五秒钟后,文本变为“错误...重新尝试...尝试 2/5”
重复上述操作直到尝试 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...)

【问题讨论】:

    标签: javascript ajax iframe connection-timeout


    【解决方案1】:

    问题似乎在于 timeoutontimeout 还不是某些实现的一部分:

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

    至少,它不在 Chrome 16 或 Firefox 7 中。而且,考虑到要求,这应该返回 true

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

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


    如果没有这些,您可以尝试使用 onabortsetTimeout(如您在评论中所述):

    // 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=10 尝试 5 次后过期。

    【讨论】:

    • "timeout" in new XMLHttpRequest() 在控制台中返回true。根据 MSDN,它自 IE7 以来就一直存在。我并不担心timeout 支持,因为我总是可以使用setTimeout 来模拟它。我更担心abort() 不能正常工作。
    【解决方案2】:

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

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

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

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

    【讨论】:

    • 嗯,虽然这看起来很有希望,但我试了一下,仍然没有帮助。我真的认为问题在于连接没有被中止,或者类似的东西......
    • 是的。我认为这是a 变量的问题。 rsc() 函数正在调用它,这就是我遇到错误的地方。在测试 readyState 之前,您是否设置了对 abort 的检查?
    • 事情是,我没有得到那个错误。我没有收到任何错误,只是无法加载页面...
    • 这很奇怪,因为我是。嗯,你说你用的是IE9?我也是。我不知道该说什么。
    • 嗯,很有趣。我刚收到一个合法的失败请求(500 内部服务器错误),超时/中止/重试代码运行良好。也许所有这些问题都源于我在返回错误之前使用 PHP 脚本休眠。我将奖励这个问题,因为它背后似乎有最多的研究,尽管这个问题将保持开放,以防有人能回答为什么会出现最初的问题。
    【解决方案3】:

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

    a.onreadystatechange = function() {};
    

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

    if( a.readyState > 0 && a.readyState < 4 ) {
        a.abort();
    }
    

    【讨论】:

    • 没有变化...还是有问题。
    • 嗯..我看不出有什么问题。但是,我会尝试在超时“to”函数中调用 send(),setTimeout 为 1 毫秒。这样,“to”函数在创建新请求之前就完成了。
    • 有趣的想法,但没有......仍然没有骰子。
    【解决方案4】:

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

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

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

    【讨论】:

      猜你喜欢
      • 2017-04-23
      • 2017-10-15
      • 2023-01-13
      • 2015-12-17
      • 1970-01-01
      • 2021-10-19
      • 2020-03-18
      • 2012-06-14
      • 2014-11-15
      相关资源
      最近更新 更多