Javascript 在$.ajax回调中,如何区分无法访问的服务器和导航离开的用户?

Javascript 在$.ajax回调中,如何区分无法访问的服务器和导航离开的用户?,javascript,ajax,jquery,Javascript,Ajax,Jquery,情况: 您对服务器的一些$.ajax请求仍在运行。它们都在xhr.status==0和xhr.readyState==0时出错 可能的原因: 服务器已关闭(编辑:如不可访问-未返回任何标题或任何内容) 用户单击链接/刷新页面/以其他方式导航离开 我想在第一种情况下弹出一个对话框,但忽略第二种情况。在我的完整方法中,我如何区分这两者?complete方法是在$(window).unload事件之前激发的,因此我不能用它来确定用户是否单击了。我也可以使用setTimeout来尝试等待下一个页面加

情况:

您对服务器的一些$.ajax请求仍在运行。它们都在xhr.status==0和xhr.readyState==0时出错

可能的原因:

  • 服务器已关闭(编辑:如不可访问-未返回任何标题或任何内容)
  • 用户单击链接/刷新页面/以其他方式导航离开

我想在第一种情况下弹出一个对话框,但忽略第二种情况。在我的完整方法中,我如何区分这两者?complete方法是在$(window).unload事件之前激发的,因此我不能用它来确定用户是否单击了。我也可以使用setTimeout来尝试等待下一个页面加载,但这是肮脏的。还有什么我可以做的吗?

您可以检查服务器的超时响应:

timeout:500,
error: function(jqXHR, textStatus, errorThrown) {
    if(textStatus==="timeout") {
        alert("got timeout");
    } else {
        // Some other error
    }
}
想法3 好吧,总是有可能假装来自不存在的服务器的延迟:

var running = true;
xhr.onreadystatechange = function()
{
    if( !xhr.status && !xhr.readyState )
    {
        // wait a short while to see whether the page is unloading.
        setTimeout( unloadTest, 250 );
    }
    else
    {
        running = false;
    }
}

function unloadTest()
{
    // running will be set to false by onbeforeunload, which means this
    // should only be true if there was some form of server error.
    if( running ) // Regnad? Robin Williams?
}
然后,在其他地方:

// (using generic JS, you can use $(window).bind( 'beforeunload' ...
window.onbeforeunload = function() 
{ 
     running = false;
} 
// (using generic JS, you can use $(window).bind( 'beforeunload' ...
window.onbeforeunload = function() 
{ 
     running = false;
} 
想法2 好的,如果下面的代码不起作用,那么要在
$(window.unload
之前测试的下一个dom级别事件是
window.onbeforeuload
。这是一个可行的选择吗

围绕AJAX方法:

var running = true;
xhr.onreadystatechange = function()
{
    if( !xhr.status && !xhr.readyState && running )
    {
        // warning! warning! danger Will Robinson!
        // there was a server error
    }
    else if( !xhr.status && !xhr.readyState )
    {
        // user did something... Who gives?
    }
    running = false;
}
var running = true;
// do this only once!!!
var _obunload = ( window.onbeforeunload )? window.onbeforeunload: function(){};
window.onbeforeunload = function() 
{ 
     _obunload.call( window );
     running = false;
}
xhr.onreadystatechange = function()
{
    if( !xhr.status && !xhr.readyState && running )
    {
        // warning! warning! danger Will Robinson!
        // there was a server error
    }
    else if( !xhr.status && !xhr.readyState )
    {
        // user did something... Who gives?
    }
    running = false;
}
然后,在其他地方:

// (using generic JS, you can use $(window).bind( 'beforeunload' ...
window.onbeforeunload = function() 
{ 
     running = false;
} 
// (using generic JS, you can use $(window).bind( 'beforeunload' ...
window.onbeforeunload = function() 
{ 
     running = false;
} 
原职位(显然不工作) 为什么不在窗口上设置一个标志呢

<html>
   <script type="text/javascript">
        // window.currentTime will update *first* after every page refresh.
        window.currentTime = new Date().getTime()
   </script>
   <!-- continue as normal -->
(此答案是另一个答案的摘要,为便于OP要求的澄清)
如果窗口级别标志不起作用,则要在
$(window.unload
之前测试的下一个dom级别事件是
window.onbeforeuload
。这是一个可行的选择吗

围绕AJAX方法:

var running = true;
xhr.onreadystatechange = function()
{
    if( !xhr.status && !xhr.readyState && running )
    {
        // warning! warning! danger Will Robinson!
        // there was a server error
    }
    else if( !xhr.status && !xhr.readyState )
    {
        // user did something... Who gives?
    }
    running = false;
}
var running = true;
// do this only once!!!
var _obunload = ( window.onbeforeunload )? window.onbeforeunload: function(){};
window.onbeforeunload = function() 
{ 
     _obunload.call( window );
     running = false;
}
xhr.onreadystatechange = function()
{
    if( !xhr.status && !xhr.readyState && running )
    {
        // warning! warning! danger Will Robinson!
        // there was a server error
    }
    else if( !xhr.status && !xhr.readyState )
    {
        // user did something... Who gives?
    }
    running = false;
}

不,您什么也没有收到-服务器无法访问。因此xhr.getAllResponseHeaders()以任何方式返回空字符串。jqXhr也是如此。getAllResponseHeaders()textStatus在这两种情况下都是“错误”。这里没有适用的“超时”…啊,我明白你的意思了。但是你真的改变了问题所在——我不需要超时,因为AJAX在任何情况下都会快速返回。使用超时将检查服务器是否慢,而不是服务器是否停机。“服务器慢”和“服务器停机”对于用户bro是相同的。这就是超时的原因。另外,如果你收到一个错误,这是一件好事,因为它显然不是由用户点击链接触发的。+1解决了这个问题。也许不需要将其附加到窗口,而是可以将其放在进行ajax调用的作用域中?通过这种方式,可以以相同的方式进行多个ajax调用并监视它们,而不会产生冲突。这实际上并不能解决问题。无论如何,新页面并没有真正进入等式,因此winTime===window.currentTime在这两种情况下仍然是真的。此时页面还没有卸载。@tjameson您基本上需要一些外部常量,它可以同时跟踪多个调用。我想要一个实用程序类。@Adam我刚才建议
window.onbeforeuload
。这样行吗?(是的,我知道,它是专有的,但MS、Chrome和FF似乎都支持它)是的,我很想这样做,但在这个循环中仍然太晚了(至少对于Chrome来说)。发生的情况是,一旦用户单击,AJAX请求就会被终止,但卸载事件直到下一页加载完成(并开始渲染)后才会触发。在再次卸载之前,我将再次检查,以确保它不起作用。上次我尝试的时候有点奇怪。我还没有编辑权限,但对于任何试图使用它的人来说:代码本身实际上不起作用,但想法是正确的-使用一个布尔指示符“用户是否单击了”,默认为true,但在onbeforeunload中设置为false。使用该布尔值来区分“AJAX失败,因为服务器没有响应”(布尔值为true)和“当用户导航离开页面时AJAX被取消”(布尔值为false)之间的区别。