node.js http.get 在向远程站点发出 5 次请求后挂起

Posted

技术标签:

【中文标题】node.js http.get 在向远程站点发出 5 次请求后挂起【英文标题】:node.js http.get hangs after 5 requests to remote site 【发布时间】:2013-06-02 16:01:16 【问题描述】:

我正在编写一个简单的 api 端点来确定我的服务器是否能够访问互联网。它工作得很好,但是在 5 个请求之后(每次都是 5 个)请求挂起。当我将 Google 切换到 Hotmail.com 时也会发生同样的事情,这让我觉得这是我的目标。我需要关闭 http.get 请求吗?我的印象是这个函数会自动关闭请求。

// probably a poor assumption, but if Google is unreachable its generally safe to say     that the server can't access the internet
// using this client side in the dashboard to enable/disable internet resources

app.get('/api/internetcheck', function(req, res) 
console.log("trying google...");
    http.get("http://www.google.com", function(r)
        console.log("Got status code!: " +r.statusCode.toString());
        res.send(r.statusCode.toString());
        res.end();
        console.log("ended!"); 
    ).on('error', function(e) 
        console.log("Got error: " + e.message);
    );
);

【问题讨论】:

具有“res.end()”行似乎会使浏览器“挂起”(即 Chrome 会在加载页面时卡住)。删除将导致状态代码成功呈现(无论这些请求发出多少次或多快 - 我在 for 循环中尝试了 100 次,一切顺利)。 【参考方案1】:

这是 “正好 5”的原因:https://nodejs.org/docs/v0.10.36/api/http.html#http_agent_maxsockets

在内部,http 模块使用代理类来管理 HTTP 请求。默认情况下,该代理最多允许 5 个打开的连接到同一 HTTP 服务器。

在您的代码中,您不会使用 Google 发送的实际响应。因此代理假定您尚未完成请求,并将保持连接打开。因此,在 5 次请求之后,代理将不再允许您创建新连接,并将开始等待任何现有连接完成。

显而易见的解决方案是只使用数据:

http.get("http://www.google.com", function(r)
  r.on('data', function()  /* do nothing */ );
  ...
);

如果您遇到/api/internetcheck 路由被大量调用的问题,因此您需要允许超过 5 个并发连接,您可以增加连接池大小,或者完全禁用代理(尽管您在这两种情况下仍需要使用数据);

// increase pool size
http.globalAgent.maxSockets = 100;

// disable agent
http.get( hostname : 'www.google.com', path : '/', agent : false , ...)

或者也许使用HEAD 请求而不是GET

(PS:如果http.get产生错误,你仍然应该使用res.end()或类似的东西来结束HTTP响应)。

注意:在 Node.js 版本 >= 0.11 中,maxSockets 设置为 Infinity

【讨论】:

只是为了补充这个出色的答案 - 我的问题是当我从远程服务器加载 PNG blob 时,在没有匹配的博客的情况下,我默认为默认二进制 blob 而不是返回404 错误。我遇到了这个问题,因为我没有使用加载的数据......非常聪明!所以如上所述 - include r.on('data', function() /* do nothing */ );它会欺骗它认为你这样做并关闭连接! 恢复一个相当老的帖子,但是,消费要求是否也适用于非 200 响应?如果你得到类似 4xx 或 5xx 的东西并且不使用 r.on('data') 进行消费,那么该连接是否没有关闭? @Johnny 我想这将取决于(某种程度上)远程服务器,但即使对于非 200 响应,我认为您应该假设您需要在 http 模块之前阅读整个响应将连接返回到池中。 @robertklep 是的,你说得对,我也添加了一些东西来应对不良反应,然后挂断停止了! @matt 看到了光,最近的 Node 版本设置了 Infinity 的限制。【参考方案2】:

如果您等待的时间足够长,5 个请求将超时,接下来的 5 个请求将被处理,因此应用程序不会真正挂起,因为它最终会处理所有请求。

要加快处理速度,您需要对响应数据进行处理,例如 r.on('data', function() );

【讨论】:

以上是关于node.js http.get 在向远程站点发出 5 次请求后挂起的主要内容,如果未能解决你的问题,请参考以下文章

如何在向某些站点发出 HttpWebRequest 时修复“底层连接已关闭:连接已意外关闭”

Node.JS 中的 HTTP DELETE 动词

Elasticsearch:使用 Filebeat 从 Node.js Web 应用程序提取日志

Elasticsearch:使用 Filebeat 从 Node.js Web 应用程序提取日志

使用 Node.js HTTP 服务器获取和设置单个 Cookie

从 ExtJS 向 node.js 请求时出现 CORS 问题。请求或响应标头不正确?