【问题标题】:Inconsistent browser retry behaviour for timed out POST requests超时 POST 请求的浏览器重试行为不一致
【发布时间】:2013-02-15 19:02:59
【问题描述】:

当由于超时而没有来自服务器的响应时,我偶尔会重试 POST 请求。所有现代浏览器都有幂等请求(GET、HEAD 等)的重试逻辑,但我无法解释为什么它会发生在 POST 请求中。

我正在使用带有 3 个路由和 chrome 浏览器的简单 node.js 服务器测试这个案例。

/       : gives a html page with jquery and code snippets to fire ajax requests
/hi     : gives a text response 'hello'
/sleep  : request will timeout without any response 

默认情况下,node.js http 服务器会在 2 分钟后超时。

重试.js

var http = require('http');
var server = http.createServer();

server.on('request', function(req, res) {
    console.log(new Date() + ' ' + req.method + ' request on ' + req.url);

    if (req.url === '/sleep') {
        console.log('!!! sleeping');
    } else if (req.url === '/') {
        html = "$.post('/hi', {'for':'server'}, function() { console.log(arguments) } ).error(function() { console.log(arguments) })";
        html += "<br><br>";
        html += "$.post('/sleep', {'for':'infinite'}, function() { console.log(arguments) } ).error(function() { console.log(arguments) })";
        html += '<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>';
    
        res.writeHead(200, {'Content-Type': 'text/html'});
        res.end(html);
    } else {
        res.writeHead(200, {'Content-Type': 'text/plain'});
        res.end('hello');
    }
});

server.listen(2020);
console.log('server listening on port 2020');

运行它

$ node retry.js 
server listening on port 2020

1

Load this page in browser http://localhost:2020

Fri Mar 01 2013 12:21:59 GMT+0530 (IST) GET request on /
Fri Mar 01 2013 12:21:59 GMT+0530 (IST) GET request on /favicon.ico

2

从开发控制台,使用 jquery 向 /hi 发起一个 ajax POST 请求

$.post('/hi', {'for':'server'}, function() { console.log(arguments) } ).error(function() { console.log(arguments) })

2013 年 3 月 1 日星期五 12:22:05 GMT+0530 (IST) POST 请求在 /hi

3

向 /sleep 发出 POST 请求,2 分钟后重试,4 分钟后出错。

$.post('/sleep', {'for':'infinite'}, function() { console.log(arguments) } ).error(function() { console.log(arguments) })

服务器日志显示 2 个请求

Fri Mar 01 2013 12:22:21 GMT+0530 (IST) POST request on /sleep
!!! sleeping
Fri Mar 01 2013 12:24:21 GMT+0530 (IST) POST request on /sleep
!!! sleeping

再次触发,2分钟后出错,无需重试。

Fri Mar 01 2013 12:30:01 GMT+0530 (IST) POST request on /sleep
!!! sleeping ?

在我们向 /hi(或任何其他 url)发出请求并导致响应之前,它不会被重试。并且仅对一个后续请求 /sleep 进行重试。

在浏览器中,网络标签显示类似

/hi - success 
/sleep - cancelled - 4 mins (retry happens)
/sleep - cancelled - 2 mins (no retry)
/sleep - cancelled - 2 mins (no retry)
/hi - success 
/sleep - cancelled - 4 mins (retry happens)
/sleep - cancelled - 2 mins (no retry)
/sleep - cancelled - 2 mins (no retry)

问题

虽然我们需要设计我们的网络应用程序来容忍这些额外的请求(浏览器或任何其他中介),但这种不一致的浏览器重试看起来很奇怪。我在 chrome (v16 & v24) 和 firefox 中观察到了这种行为。

谁能帮我理解超时非幂等请求背后的浏览器重试逻辑?

其他相关的 stackoverflow 问题

What happens when no response is received for a request? I'm seeing retries

【问题讨论】:

  • 这可能是 jquery 的问题吗?
  • @Floby 我曾尝试使用 jquery、原型、纯 html 表单进行 POST 请求,并且仅使用浏览器栏发出 GET 请求。这种行为保持不变。 Firefox 和 chrome 都会发生这种情况。
  • 为了排除 node.js,我尝试过使用 curl 和 w3m 等命令行客户端。请求按预期在 2 分钟内超时,不再重试。 NODE_DEBUG=http,net node retry.js 清楚地显示了在重试时建立的新连接。

标签: node.js http google-chrome


【解决方案1】:

当连接关闭时,浏览器会在收到服务器响应之前重试请求(包括 POST)。这是在HTTP 1.1 Spec Section 8.2.4 中定义的。

【讨论】:

  • 这回答了这个场景。我们使我们的应用程序对中间重试具有弹性。谢谢。
  • 什么可以在收到响应之前关闭连接?我有一个持续大约 10 分钟的过程。在这里测试,在我的机器上,它工作正常。但是在另一台机器上(都带有 windows/chrome),POST 重试会在 2 或 3 分钟后触发。我不知道发生了什么。我只能考虑浏览器超时,但是为什么我的机器上没有发生呢?
  • @robsonrosa 客户端和服务器之间的反向代理或 Web 应用程序防火墙可能会关闭连接,具体取决于连接的配置方式。
猜你喜欢
  • 2015-03-28
  • 1970-01-01
  • 2015-08-08
  • 2016-09-14
  • 2017-05-14
  • 2010-11-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多