jQuery AJAX在窗口卸载时触发错误回调 - 如何过滤掉卸载并仅捕获真正的错误?

时间:2009-09-02 21:48:50

标签: javascript jquery ajax xmlhttprequest

如果我离开$ .ajax()请求中间的页面,则会触发错误回调。我已经在Safari和FF中测试了GET和POST请求。

一个可能的解决方案是在页面卸载时中止所有AJAX请求,但是在卸载之前调用错误处理程序,所以这似乎不可能。

我希望能够在客户端使用礼貌警报或模式对话框优雅地处理诸如500s之类的REAL错误,但我不希望在用户离开页面时调用此处理。 / p>

我该怎么做?

-

(也很奇怪:当离开页面时,错误处理程序会说textStatus参数是“error”,与接收500 /错误请求时抛出的相同。)

6 个答案:

答案 0 :(得分:24)

在错误回调或$.ajax中,您有三个输入参数:

function (XMLHttpRequest, textStatus, errorThrown) {
   this; // options for this ajax request
}

您可以直接检查xhr.status以获取HTTP响应代码,例如:

$.ajax({
  url: "test.html",
  cache: false,
  success: function(html){
    $("#results").append(html);
  },
  error: function (xhr, textStatus) {
    if (xhr.status == 500) {
      alert('Server error: '+ textStatus);
    }
  }
});

修改 告诉浏览器断开的连接与服务器关闭的情况(jasonmerino的评论)之间的区别:

  

在卸载时,xhr.readyState应为0,其中为非响应   服务器xhr.readyState应为4。

答案 1 :(得分:12)

在所有情况下都要正确处理这个问题。不幸的是,在许多流行的浏览器中,如果通过导航或服务器关闭/无响应取消AJAX调用,则xhr.status是相同的(0)。所以这种技术很少奏效。

这是我积累的一组高度“实用”的黑客,它们在大多数情况下都能很好地工作,但仍然不是防弹的。我们的想法是尝试捕获导航事件并设置一个在AJAX错误处理程序中检查的标志。像这样:

var global_is_navigating = false;

$(window).on('beforeunload',function() {
    // Note: this event doesn't fire in mobile safari
    global_is_navigating = true;
});

$("a").on('click',function() {
    // Giant hack that can be helpful with mobile safari
    if( $(this).attr('href') ) {
        global_is_navigating = true;
    }
});

$(document).ajaxError(function(evt, xhr, settings) {
    // default AJAX error handler for page
    if( global_is_navigating ) {
        // AJAX call cancelled by navigation. Not a real error
        return;
    }
    // process actual AJAX error here.
});

答案 2 :(得分:4)

(我会将此作为对主要答案的评论添加,但还没有积累足够的分数来执行此操作!)

我也在FF4和Chrome(9.0.597.107)中看到了这一点。可能在其他地方,但这对我来说很难解决它!

关于这种情况的一个奇怪的事情是返回的XMLHttpRequest.status === 0

这似乎是检测这种情况的可靠方法,在我的特定情况下,会中止向用户显示的自定义错误处理:

error: function (XMLHttpRequest, textStatus, errorThrown) {
    if (XMLHttpRequest.status === 0) return;
    // error handling here
}

另外值得一提的是,假设在浏览器返回$ .ajax()调用的JSON解析中可能存在问题,我还尝试更换Douglas Crockford版本的原生JSON.stringify (https://github.com/douglascrockford/JSON-js)但没有区别。

答案 3 :(得分:0)

错误回调应该获得对XHR对象的引用,检查状态代码以查看它是否是服务器错误?

答案 4 :(得分:0)

如果您使用jQuery函数,例如$.get$.post$.ajax ...那么您可以使用参数text_status来检查哪种类型的失败是:

request = $.get('test.html', function(data){
    //whatever
}).fail(function(xhr, text_status, error_thrown) {

    if(text_status!== 'abort'){
        console.warn("Error!!");
    }
});

来自jQuery docs

  

jqXHR.fail(function(jqXHR,textStatus,errorThrown){}); 错误回调选项的替代构造,.fail()方法   替换已弃用的.error()方法。请参阅deferred.fail()   实施细节。

答案 5 :(得分:0)

请稍等片刻,然后显示错误。如果由于页面卸载而导致请求失败,则不会触发超时,并且不会显示错误。我的实验表明,对于桌面Safari和Firefox(台式机和Android)而言100毫秒就足够了,对于iOS Safari而言500毫秒就足够了。持续时间是模糊的,因此,如果可能的话,应增加数字。

const request = new XMLHttpRequest();

// Firefox calls onabort, Safari calls onerror
request.onabort = request.onerror = () => {
  // A short comprehensive solution
  setTimeout(() => {
    alert('The request has failed completely');
  }, 500);

  // A more gentle solution
  const isWebKit = 'ApplePayError' in window;
  const isDesktopSafari = !('standalone' in navigator);
  const isGecko = 'mozInnerScreenX' in window
  setTimeout(
    () => {
      alert('The request has failed completely');
    },
    isWebKit ? (isDesktopSafari ? 100 : 500) : (isGecko ? 100 : 0) 
  );
}

request.open('get', 'http://example.com', true);
request.send();

我仅在现代浏览器(Chrome 87,Firefox 83,IE 11,Edge,Safari 14)中检查了此解决方案。