【问题标题】:Long running AJAX request resubmits after a couple of minutes长时间运行的 AJAX 请求在几分钟后重新提交
【发布时间】:2016-03-19 20:42:31
【问题描述】:

我有一个长时间运行的服务调用,我使用 jQuery.ajax 进行调用。该服务可能需要 2 分钟以上才能完成。

AJAX 请求已提交,但预计没有响应。一个单独的 AJAX 请求报告操作的进度。

在某些站点上,我们发现代理会在 2 分钟后自行重新提交 Ajax 请求。浏览器是 Chrome,但我怀疑它与 Chrome 相关。

这绝对不是我们重新提交ajax请求的情况。为了确保我们设置了一个布尔值来防止在 beforeSend 事件中重新提交。

我现在处理此重新提交的方式是在数据请求中添加一个随机数,并且服务会在执行其操作之前测试该随机数是否已经提交。对该服务的任何第二次调用都会无害地返回,并且原始请求会继续进行。

请注意,我添加了一个无意义的服务,它只会等待 5 分钟,而且我从未遇到过测试服务的问题(在生产站点上)。

谁能告诉我是什么导致这个 ajax 重新提交,以及如何在本地复制它?

这是用来发送请求的js:

var sent = false;
var data = { ... }; // data is a very large object;

$.ajax("service.ashx?loc=area/subarea/", {
    type: "POST",
    data: data,
    traditional: true,
    error: function (jqXHR, textStatus, errorThrown) {
        if (jqXHR.status === 0) {
            // see http://stackoverflow.com/questions/3825581/does-an-http-status-code-of-0-have-any-meaning

        } else {
            ReportFailure(textStatus,errorThrown);
        }
    },
    beforeSend: function () {
        if (sent === true) {
            return false;
        }
        sent = true;
        return true;
    }
});

这是从 HTTP 存档 (HAR) 请求的 ajax,其中重新提交了请求并立即失败。注意 2 分钟的时间。

{
"startedDateTime": "2015-12-11T12:26:58.018Z",
"time": 120066.61499999973,
"request": {
  "method": "POST",
  "url": "https://example.com/service.ashx?loc=area/subarea/",
  "httpVersion": "HTTP/1.1",
  "headers": [
    ... // removed for brevity
  ],
  "queryString": [
    { "name": "loc", "value": "area/subarea/" }
  ],
  "cookies": [
    ... // removed for brevity
  ],
  "headersSize": 1163,
  "bodySize": 48048,
  "postData": {
    "mimeType": "application/x-www-form-urlencoded; charset=UTF-8",
    "text": ..., // removed for brevity
    "params": [
      ... // removed for brevity        ] }
},
"response": {
  "status": 500,
  "statusText": "Internal Server Error",
  "httpVersion": "HTTP/1.1",
  "headers": [
    {
      "name": "Date",
      "value": "Fri, 11 Dec 2015 12:28:57 GMT"
    },
    ... // removed for brevity
  ],
  "cookies": [],
  "content": {
  "size": 54,
  "mimeType": "text/xml",
  "compression": 0
  },
  "redirectURL": "",
  "headersSize": 305,
  "bodySize": 54,
  "_transferSize": 359
},
"cache": {},
"timings": {
  "blocked": 120005.055999998,
  "dns": -1,
  "connect": -1,
  "send": 1.0939999989932403,
  "wait": 59.986000001008506,
  "receive": 0.47900000172376167,
  "ssl": -1
},
"connection": "7498"

【问题讨论】:

  • 您是否检查过在重新提交时您的代码(ajax 代码)是否实际被调用...您可以在 ajax 请求之前和 beforeSend 处理程序中添加一个console.log() stmt检查这一点 - 如果您的代码确实发送了第二个请求,那么消息将在控制台中记录两次
  • 下一步可以在 ajax 行中放置一个断点以查看它是否被调用两次,以及是否查看堆栈跟踪以查看第二次调用的启动方式/位置...或者您可以使用console.trace() 日志记录查看调用堆栈
  • 我确定不是我的 ajax 请求在代码中重新提交。一方面,重新提交不会在 Chrome 网络分析器中显示为单独的请求 - 如果只是重新执行代码,就会出现这种情况。 beforeSend 没有第二次执行。
  • 是的......你是对的......在这种情况下,我认为不是客户端代码导致它......你将不得不重新查看你的服务器端代码。 ..
  • 我不确定服务器会出现什么问题。即使用户代理重新提交了请求,原始请求也会继续执行。我试图指出为什么重新提交请求。

标签: javascript jquery ajax


【解决方案1】:

同样的故事。如果到目前为止客户端没有收到响应,jQuery 显然会在 120 秒(默认超时)后重新发送请求。

增加超时时间如下:

    $.ajax({
      url: localhost,
      type: 'POST',
      timeout: 1000*60*10

不会改变游戏规则。尽管客户端继续等待任何响应,但请求仍会在 2 分钟后重新发送。

虽然服务器端能够很好地并行处理这两个请求,但客户端请求在第一个请求的有效响应时失败。

还没有解决办法

编辑:

事实证明,浏览器是重新发送事件的浏览器,并且该行为完全符合 HTTP/1.1 规范。实际上,(node.js)后端在 120 秒超时后关闭了套接字,例如 jonasnas 指出的。解决方案是在响应对象处禁用超时,如下所示:

    // this is a long running request,
    // so disable response timeout
    response.setTimeout(0);

【讨论】:

    【解决方案2】:

    如果始终在 2 分钟内处理请求,则表明您的服务器端 (node.js) 未正确完成响应(使用rsp.end())。 2 分钟是express/node 服务器上的默认超时时间。

    【讨论】:

    • 后端是.net ASHX。我已经对此进行了试验,并且不认为这是服务器超时。 ASHX 将超时​​设置为小时,即使重新提交已完成或失败,线程也会继续执行。至于 jQuery 超时,没有生效的全局超时,也没有为此实例指定超时。
    【解决方案3】:

    不幸的是,这里的所有其他(浏览器端)建议对我来说都不起作用。但是,只需让 ajax 请求立即超时就可以了:

    这可以通过以下方式实现:

    $.ajax("https://someurl/", {
      ...
      timeout:1
      ...
    });
    

    作为旁注:将超时设置为 0 不起作用。

    如果服务器端计算需要这么长时间,那么在这里等待是没有意义的。需要一个单独的解决方案来检查计算是否完成。

    这种方法看起来很糟糕。因此,仍然非常欢迎任何更好的工作解决方案;-)

    【讨论】:

      【解决方案4】:

      我们的问题是负载均衡器。当我们通过 LB url 从 AJAX 调用 web api 服务时,我们得到了 120 秒的问题,并且对服务的重复调用,没有来自客户端的代表性额外调用。 当我们通过直接服务器节点调用 api,从等式中删除负载均衡器时,我们不会遇到问题。 如果您的方程式中有负载平衡器,请调查直接调用服务器节点是否有效。如果是这样,请使用负载平衡器支持。

      作为临时解决方法,在解决 LB 问题之前,我将在页面加载时以隐藏字段将服务器节点名称返回给客户端页面,并让我的 JS 代码使用它来构造用于调用服务的直接 URL。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-01-23
        • 1970-01-01
        • 1970-01-01
        • 2013-04-03
        • 2020-03-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多