javascript - xmlhttprequest 超时/中止未按预期工作?

标签 javascript ajax iframe connection-timeout

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

预期行为:

The request is sent
After five seconds, the text changes to "Error... Retying... Attempt 2/5"
Repeat the above up until Attempt 5/5, then fail.
The five calls to the PHP file are aborted, and either there will be five files in the "test" folder, spaced 5 seconds apart, or there will be none because ignore_user_abort is off.

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

The request is sent
The attempt text appears and changes as it should
After five attempts, the error message is displayed
I am unable to load any pages for five whole minutes.
On the server, there are five files spaced one minute apart

我不知道这是怎么回事,因为在服务器端,请求 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...)

最佳答案

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

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

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

The timeout attribute must return its value. Initially its value must be zero.

两者都是 XHR 2 spec 的一部分自 Sept 7, 2010 .但是,由于“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 次尝试过期。

关于javascript - xmlhttprequest 超时/中止未按预期工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8995085/

相关文章:

javascript - 有时网站前端的变化不会反射(reflect)在浏览器中并加载旧版本的网站

javascript - body 动画不流畅

php - JQuery AJAX 请求答案但没有成功

iframe - 是否可以让 oAuth 留在 iFrame 中而不占用父窗口?

jquery - 无法在Fancybox中加载YouTube视频-空白页

javascript - 按下按钮时使背景处于非事件状态

javascript - jQuery -> mouseEnter 更改 css 直到数字

jQuery ajax 完成后调用执行函数

javascript - "active"AJAX 分页中的类不起作用

html - 标题属性工具提示和 iframe