简体   繁体   English

Ajax请求有时会失败 - 有和没有jQuery

[英]Ajax request failing sometimes - with and without jQuery

Introduction 介绍

This question seems longer than it actually is, but I tried to keep a clean structure. 这个问题似乎比实际更长,但我试图保持一个干净的结构。

To start off, I have this webapp which needs to be very small in filesize to be able to load completely (without cache) on your smartphone in < 10s. 首先,我有这个webapp,它需要在文件大小非常小,以便能够在<10s内完全加载(无缓存)智能手机。 This requires me to not use a library like jQuery (which doesn't matter anyway, see below). 这要求我不要使用像jQuery这样的库(无论如何都没关系,见下文)。

Without jQuery 没有jQuery

I basically used the MDN Ajax page to create this short wrapper: 我基本上使用MDN Ajax页面来创建这个简短的包装器:

function ajax(options) {
    var request;

    if (window.XMLHttpRequest) {
        request = new XMLHttpRequest();
    } else {
        request = new ActiveXObject("Microsoft.XMLHTTP");
    }

    request.timeout = 6500;
    request.ontimeout = function () {
        // not called, 6.5s is too high for a timeout anyway, checked this one first
        options.error(request);
    };

    request.onreadystatechange = function () {
        if (request.readyState == 4) {
            if (request.status >= 200 && request.status < 400) {
                options.success(request.responseText);
            } else {
                options.error(request);
            }
        }
    };

    request.open("GET", options.url, true);
    request.send();
}

However, sometimes (in like 1/15 up to to 1/100 cases) the request fails. 但是,有时(在1/15到1/100的情况下)请求失败。 I get a request object similar to this one: 我得到一个类似于这个的请求对象:

XMLHttpRequest { 
    onreadystatechange: ajax/request.onreadystatechange(), 
    readyState: 4, 
    timeout: 6500, 
    withCredentials: false, 
    upload: XMLHttpRequestUpload, 
    responseURL: "my-url", 
    status: 0, // <-- this seems to be the main problem
    statusText: "",
    responseType: "",
    response: "" 
}

To point this out, I'm not trying to do CORS here, it's all on the same domain. 要说明这一点,我不是想在这里做CORS,它都在同一个域上。 Also the timeout is set to 6.5s, if I look at the other requests, they usually complete within ~45ms. 此外,超时设置为6.5秒,如果我查看其他请求,它们通常在~45ms内完成。 I tried to "retry" the Ajax 3x if it fails once, to catch the "status = 0"-problem, however this didn't always work out yet as it still occured and 0 means the webserver didn't deliver any content (this workaround just seems like a really dirty hack). 我尝试“重试”Ajax 3x,如果它失败一次,赶上“status = 0” - 问题,但是这并不总是有效,因为它仍然发生,0表示网络服务器没有提供任何内容(这种解决方法似乎是一个非常脏的黑客)。

With jQuery Ajax 使用jQuery Ajax

On another project I'm using jQuery because I don't have these size limits. 在另一个项目我使用jQuery因为我没有这些大小限制。 I'm using a regular jQuery.ajax call, just like this: 我正在使用常规的jQuery.ajax调用,就像这样:

$.ajax({
    url: url,
    dataType: "json",
    success: options.updateSuccess,
    error: options.updateError,
    timeout: options.updateTimeout
});

However even this one sometimes fails with statusCode = 0 (the updateTimeout is set to 65s as I "can wait for this one"). 然而,即使这个有时也失败,statusCode = 0( updateTimeout设置为65s,因为我“可以等待这个”)。 Also it's a different webserver than in the first snippet. 它也是一个与第一个片段不同的网络服务器。

What have I tried so far? 到目前为止我尝试了什么?

  • do some research (turns out many people wanted to use CORS which I'm not trying to do) 做一些研究(结果很多人都想使用我不想做的CORS)
  • preventing the browser to use a cached version of the site by appending a timestamp to the url ( "&cache=" + new Date().getTime() , didn't work too) 通过在URL上附加时间戳来阻止浏览器使用网站的缓存版本( "&cache=" + new Date().getTime() ,也不起作用)
  • check the webserver for wrong configuration (it wasn't the source of this problem, I even tried polling the site with a short Python script in the same intervals like the Ajax calls and they all succeeded) 检查Web服务器是否有错误的配置(这不是这个问题的根源,我甚至尝试使用简短的Python脚本在Ajax调用的相同时间间隔内查询站点,它们都成功了)
  • tried different browsers: this mainly happens in Firefox, although Chrome also seems to fail once in a while 尝试过不同的浏览器:这主要发生在Firefox中,虽然Chrome似乎偶尔也会失败

Final Question 最后的问题

Why does this happen then? 为什么会这样呢? I'm not capable of reproducing it repeatedly, it just sometimes happens. 我不能反复复制它,它有时会发生。 Is this a browser bug that makes every n-th Ajax call fail? 这是一个浏览器错误,使每个第n个Ajax调用失败吗? Do you have any different approaches to solve this (preferably with plain Javascript)? 你有什么不同的方法来解决这个问题(最好用普通的Javascript)吗?

Update 更新

I did some more research, this time with wireshark. 我做了一些更多的研究,这次是使用wireshark。 I logged which request caused the status = 0 and then viewed the TCP flow graph of these packages and all requests got an answer from the server, I guess it's not a server side problem. 我记录了哪个请求导致status = 0 ,然后查看了这些包的TCP流程图,所有请求都得到了服务器的答案,我想这不是服务器端问题。

So I resolved both problems by doing a lot of tests. 所以我通过做了很多测试来解决这两个问题。 The jQuery one was quite easy, updating to jQuery 2.1.4 solved it, I don't want to know what was causing this, it just works now. jQuery一个很简单,更新到jQuery 2.1.4解决了它,我不想知道是什么导致了这个,它现在才起作用

For the second problem I reduced the timeout to 500ms and then ran into a timeout which led me to onreadystate being called even though the request didn't finish (in terms of getting an answer in time) completely thus getting status = 0 . 对于第二个问题,我将超时减少到500毫秒,然后进入超时,这导致我的onreadystate被调用,即使请求没有完成(在获得及时的答案方面),因此获得status = 0 Why this happened before, see above. 为什么会发生这种情况,见上文。 To make sure that the timeout was not just "random" I added a retry counter and modified my Ajax function: 为了确保超时不仅仅是“随机”,我添加了一个重试计数器并修改了我的Ajax函数:

function ajax(options) {
    var request;

    if (options.retry === undefined) {
        options.retry = 3; // modify here for default retry count
    }

    if (window.XMLHttpRequest) {
        request = new XMLHttpRequest();
    } else {
        request = new ActiveXObject("Microsoft.XMLHTTP");
    }

    request.timeout = options.timeout ? options.timeout : 500; // modify here for default timeout
    request.ontimeout = function () {
        if (options.retry > 0) {
            options.retry--;
            ajax(options);
        } else {
            options.error(request);
        }
    };

    request.onreadystatechange = function () {
        var delta = new Date().getTime() - request.startTime;

        if (request.readyState == 4) {
            if (request.status >= 200 && request.status < 400) {
                options.success(request.responseText);
            } else if (request.status === 0 && delta >= request.timeout) {
                // do nothing as this was "just a timeout"
            } else {
                options.error(request);
            }
        }
    };

    request.startTime = new Date().getTime();
    request.open("GET", options.url, true);
    request.send();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM