如何在 Node.js 中调试错误 ECONNRESET?

Posted

技术标签:

【中文标题】如何在 Node.js 中调试错误 ECONNRESET?【英文标题】:How do I debug error ECONNRESET in Node.js? 【发布时间】:2013-06-19 05:06:41 【问题描述】:

我正在运行一个使用 Socket.io 的 Express.js 应用程序,用于聊天网络应用程序 我在 24 小时内随机收到大约 5 次以下错误。 节点进程被永远包裹,它会立即重新启动。

问题是重新启动 Express 会将我的用户踢出他们的房间 没有人想要那样。

Web 服务器由 HAProxy 代理。没有套接字稳定性问题, 只使用 websockets 和 flashsockets 传输。 我不能故意复制这个。

这是 Node v0.10.11 的错误:

    events.js:72
            throw er; // Unhandled 'error' event
                  ^
    Error: read ECONNRESET     //alternatively it s a 'write'
        at errnoException (net.js:900:11)
        at TCP.onread (net.js:555:19)
    error: Forever detected script exited with code: 8
    error: Forever restarting script for 2 time

编辑 (2013-07-22)

添加了 socket.io 客户端错误处理程序和未捕获的异常处理程序。 似乎这个抓住了错误:

    process.on('uncaughtException', function (err) 
      console.error(err.stack);
      console.log("Node NOT Exiting...");
    );

所以我怀疑这不是 Socket.io 问题,而是对另一台服务器的 HTTP 请求 我做的或 mysql/Redis 连接。问题是错误堆栈 不能帮助我识别我的代码问题。这是日志输出:

    Error: read ECONNRESET
        at errnoException (net.js:900:11)
        at TCP.onread (net.js:555:19)

我怎么知道是什么原因造成的?如何从错误中获得更多信息?

好的,不是很冗长,但这是 Longjohn 的堆栈跟踪:

    Exception caught: Error ECONNRESET
     [Error: read ECONNRESET]
      code: 'ECONNRESET',
      errno: 'ECONNRESET',
      syscall: 'read',
      __cached_trace__:
       [  receiver: [Object],
           fun: [Function: errnoException],
           pos: 22930 ,
          receiver: [Object], fun: [Function: onread], pos: 14545 ,
         ,
          receiver: [Object],
           fun: [Function: fireErrorCallbacks],
           pos: 11672 ,
          receiver: [Object], fun: [Function], pos: 12329 ,
          receiver: [Object], fun: [Function: onread], pos: 14536  ],
      __previous__:
        [Error]
         id: 1061835,
         location: 'fireErrorCallbacks (net.js:439)',
         __location__: 'process.nextTick',
         __previous__: null,
         __trace_count__: 1,
         __cached_trace__: [ [Object], [Object], [Object] ]  

这里我提供闪存套接字策略文件:

    net = require("net")
    net.createServer( (socket) =>
      socket.write("<?xml version=\"1.0\"?>\n")
      socket.write("<!DOCTYPE cross-domain-policy SYSTEM \"http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd\">\n")
      socket.write("<cross-domain-policy>\n")
      socket.write("<allow-access-from domain=\"*\" to-ports=\"*\"/>\n")
      socket.write("</cross-domain-policy>\n")
      socket.end()
    ).listen(843)

这可能是原因吗?

【问题讨论】:

@GottZ 也许这可以帮助(与在节点 js 中工作的人交谈)gist.github.com/samsonradu/1b0c6feb438f5a53e30e。我今天将部署 socket.error 处理程序并通知您。 @Gottz socket.error 句柄没有帮助,但 process.on('uncaughtException') 捕获了错误。这是错误的console.log: [Error: read ECONNRESET] code: 'ECONNRESET', errno: 'ECONNRESET', syscall: 'read' ECONNRESET 可能来自网络问题。如您所知,在测试时不可能捕获所有异常。有些会出现在您的生产服务器上。您将不得不使您的服务器健壮。您可以使用 Redis 作为存储来处理会话删除。即使您的节点服务器出现故障,它也会使您的会话持续存在。 为什么这与会话删除有关?无论如何,它们都由 Redis 处理。 您至少有一个未设置处理程序的 TCP 套接字侦听。所以现在是时候检查那个在哪里了:D 【参考方案1】:

您可能已经猜到了:这是连接错误。

“ECONNRESET” 表示 TCP 会话的另一端突然关闭了它的连接端。这很可能是由于一个或多个应用程序协议错误造成的。您可以查看 API 服务器日志,看看它是否抱怨了什么。

但由于您也在寻找一种方法来检查错误并可能调试问题,因此您应该查看 "How to debug a socket hang up error in NodeJS?" 发布在 *** 上的类似内容问题。

快速而肮脏的开发解决方案

使用longjohn,您将获得包含异步操作的长堆栈跟踪。

清洁正确的解决方案: 从技术上讲,在节点中,只要you emit an 'error' event and no one listens to it, it will throw。为了让它不抛出,在它上面放一个监听器并自己处理它。这样您就可以记录错误并提供更多信息。

要为一组调用设置一个侦听器,您可以使用domains 并在运行时捕获其他错误。确保与 http(Server/Client) 相关的每个异步操作与代码的其他部分相比位于不同的 domain 上下文中,域将自动侦听 error 事件并将其传播到它自己的处理程序。所以你只听那个处理程序并获取错误数据。 You also get more information for free.

编辑 (2013-07-22)

正如我上面写的:

“ECONNRESET” 表示 TCP 会话的另一端突然关闭了它的连接端。这很可能是由于一个或多个应用程序协议错误造成的。您可以查看 API 服务器日志,看看它是否抱怨了什么。

也可能是这种情况:在随机时间,另一端过载并因此简单地终止连接。如果是这种情况,则取决于您要连接的确切内容……

但有一件事是肯定的:您的 TCP 连接上确实存在读取错误,这会导致异常。您可以通过查看您在编辑中发布的错误代码来确认这一点。

【讨论】:

它不一定意味着“突然关闭”。它通常是由于写入对等方已经正常关闭的连接而导致的。这将导致它发出 RST。 @EJP 我“突然”写作是有充分理由的。错误(不是警告)表明连接已被对等方重置。 现有连接被远程对等方强制关闭。 强制关闭是突然的,因为意外! (如果远程机器上的对等应用程序突然停止,机器重新启动,或对等应用程序在远程套接字上使用“硬关闭”,这通常会导致。如果连接由于“保持活动”活动而中断,也可能导致此错误在一个或多个操作正在进行时检测到故障……这些操作和后续操作将失败。) 当我从浏览器 (Chrome) 几乎同时批量发送大约 100 个 API 调用以进行测试时,我收到此错误。我想 Chrome 必须变得超载并终止一些连接......@Samson - 在自己的域中处理每个请求并在不重新启动服务器的情况下捕获域错误有什么问题? @supershnee 您几乎应该总是在发生未捕获的异常后重新启动服务器,因为您的数据、应用程序和 node.js 本身处于未知状态。出现异常后继续操作会给您的数据带来风险。如果您想了解更多信息,请查看Node's docs on process 或Node's docs on domains。【参考方案2】:

我为提供闪存策略文件而使用的一个简单的 tcp 服务器导致了这种情况。我现在可以使用处理程序捕获错误:

# serving the flash policy file
net = require("net")

net.createServer((socket) =>
  //just added
  socket.on("error", (err) =>
    console.log("Caught flash policy server socket error: ")
    console.log(err.stack)
  )

  socket.write("<?xml version=\"1.0\"?>\n")
  socket.write("<!DOCTYPE cross-domain-policy SYSTEM \"http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd\">\n")
  socket.write("<cross-domain-policy>\n")
  socket.write("<allow-access-from domain=\"*\" to-ports=\"*\"/>\n")
  socket.write("</cross-domain-policy>\n")
  socket.end()
).listen(843)

【讨论】:

代码有问题吗?我应该在写之前检查套接字是否可写吗? Doh,在我发布几乎相同的内容之前,您没有看到您已经找到了解决方案:) 至于您的问题,即使您检查套接字是否可写,也可能不是当您在几微秒后写入它并且仍然会引发错误时,因此这是确定的“方式”。 好的,如果这样的话有安全的出路吗?像错误处理程序中的 socket.close() 一样?因为我认为这些错误后我的 CPU 负载正在增加(不确定) 我一直在错误处理程序中调用socket.destroy() 以确保。遗憾的是,我找不到是否需要的文档,但这样做不会发出错误。 socket.destroy() 拯救了我的一天,不管它如何工作!谢谢!【参考方案3】:

我遇到了类似的问题,即在升级 Node.js 后应用程序开始出错。我相信这可以追溯到Node release v0.9.10这个项目:

net:不要抑制 ECONNRESET (Ben Noordhuis)

以前的版本不会因客户端中断而出错。来自客户端的连接中断会在 Node.js 中引发错误 ECONNRESET。我相信这是 Node 的预期功能,所以修复(至少对我来说)是处理错误,我相信你在未捕获的异常中做了。虽然我在 net.socket 处理程序中处理它。

你可以证明这一点:

制作一个简单的套接字服务器并获取 Node v0.9.9 和 v0.9.10。

require('net')
    .createServer( function(socket) 
    
           // no nothing
    )
    .listen(21, function()
     
           console.log('Socket ON')
    )

使用 v0.9.9 启动它,然后尝试 FTP 到此服务器。我使用 FTP 和端口 21 只是因为我在 Windows 上并且有一个 FTP 客户端,但没有方便的 telnet 客户端。

然后从客户端,断开连接。 (我只是在做 Ctrl-C)

您应该在使用 Node v0.9.9 时看到 NO ERROR,在使用 Node v.0.9.10 及更高版本时应该看到 ERROR。

在生产中,我使用 v.0.10。一些东西,它仍然给出错误。同样,我认为这是有意的,解决方案是处理代码中的错误。

【讨论】:

谢谢,我自己搞定了!重要的是不要让错误传播到 uncaughtException,因为它会使整个应用程序变得不稳定。例如。在捕获大约 10 个 ECONNRESET 错误后,服务器有时会变得无响应(只是冻结并且没有处理任何连接) 也知道节点版本更改不再抑制错误,但是看到每个版本都出现并解决了这么多问题,我宁愿选择最新的。我现在正在使用 V0.10.13 顺便说一句【参考方案4】:

今天遇到了同样的问题。 经过一番研究,我发现了一个非常有用的--abort-on-uncaught-exception node.js option。它不仅提供了更详细和有用的错误堆栈跟踪,而且还保存了应用程序崩溃时的核心文件,以便进一步调试。

【讨论】:

奇怪的是,我正在寻找这个旧问题的新答案——但这很好,谢谢【参考方案5】:

我遇到了同样的问题,但我通过放置:

server.timeout = 0;

server.listen 之前。 server 是这里的 HTTP 服务器。根据API documentation,默认超时为 2 分钟。

【讨论】:

这不是一个解决方案,而是一个快速修复,它可以在不引发错误的情况下破坏事物。 我相信问题是它在 5 分钟左右后超时,这仍然是个问题吗? 没有超时可能会让你通过 http 向量容易受到 DOS 攻击【参考方案6】:

我在开发过程中也遇到了 ECONNRESET 错误,我解决它的方法是使用 nodemon 启动我的服务器,只需使用"node server.js" 启动我的服务器即可解决我的问题。

这很奇怪,但它对我有用,现在我再也看不到 ECONNRESET 错误了。

【讨论】:

知道您是如何提出这个解决方案的吗?你只是随便试了一下。这对我也有帮助。【参考方案7】:

另一种可能的情况(但很少见)是,如果您有服务器到服务器的通信并将 server.maxConnections 设置为非常低的值。

在节点的核心库 net.js 中,它会调用 clientHandle.close(),这也会导致错误 ECONNRESET:

if (self.maxConnections && self._connections >= self.maxConnections) 
  clientHandle.close(); // causes ECONNRESET on the other end
  return;

【讨论】:

很好的调用,但maxConnections 默认值为Infinity。只有当您明确覆盖该值时,才会出现这种情况(如您所说)。【参考方案8】:

是的,您提供的策略文件肯定会导致崩溃。

要重复,只需在您的代码中添加延迟:

net.createServer( function(socket) 

    for (i=0; i<1000000000; i++) ;
    socket.write("<?xml version=\"1.0\"?>\n");
…

... 并使用telnet 连接到端口。如果您在延迟到期之前断开 telnet,当 socket.write 抛出错误时,您将遇到崩溃(未捕获的异常)。

为了避免这里的崩溃,只需在读/写套接字之前添加一个错误处理程序:

net.createServer(function(socket)

    for(i=0; i<1000000000; i++);
    socket.on('error', function(error)  console.error("error", error); );
    socket.write("<?xml version=\"1.0\"?>\n");

当您尝试上述断开连接时,您只会收到一条日志消息,而不是崩溃。

完成后,请记住消除延迟。

【讨论】:

【参考方案9】:

我也遇到了这个错误,经过几天的调试和分析,终于解决了:

我的解决方案

对我来说,VirtualBox(用于 Docker)是问题所在。我在我的虚拟机上配置了端口转发,错误只发生在转发的端口上。

一般结论

以下观察结果可能会为您节省我必须投入的工作时间:

对我来说,这个问题只发生在一个端口上从 localhost 到 localhost 的连接上。 -> 检查更改这些常量中的任何一个都可以解决问题。 对我来说,问题只发生在我的机器上 -> 让其他人尝试一下。 对我来说,问题只是在一段时间后才出现,无法可靠地重现 无法使用任何节点或 expresses(调试)工具检查我的问题。 -> 不要在这上面浪费时间

->确定您的网络(设置)是否有问题,例如虚拟机、防火墙等,这可能是问题的原因。

【讨论】:

【参考方案10】:

ECONNRESET 在服务器端关闭 TCP 连接并且您对服务器的请求未完成时发生。服务器响应连接的消息,您指的是无效连接。

为什么服务器发送一个无效连接的请求?

假设您在客户端和服务器之间启用了保持连接。保持活动超时配置为 15 秒。这意味着如果keep-alive空闲15秒,它将发送连接关闭请求。所以 15 秒后,服务器告诉客户端关闭连接。 但是,当服务器发送这个请求时,客户端正在向服务器端发送一个已经在飞行中的新请求。由于此连接现在无效,服务器将拒绝并显示 ECONNRESET 错误。所以问题是由于对服务器端的请求较少。所以请禁用keep-alive,它会正常工作的。

【讨论】:

【参考方案11】:

我通过简单地连接到不同的网络解决了这个问题。这是可能的问题之一。

如上所述,ECONNRESET 意味着 TCP 会话突然关闭了它的连接端。

您的互联网连接可能会阻止您连接到某些服务器。就我而言,我试图连接到 mLab(托管 MongoDB 数据库的云数据库服务)。我的 ISP 阻止了它。

【讨论】:

这个对我有用,我几个小时前运行良好的代码突然停止工作,结果是网络更改导致了问题 两位,谢谢 :) 我连接到一个非常差的 wifi(但不知道),我切换到另一个 wifi 扩展器来解决它。跨度> 【参考方案12】:

我已经通过以下方式解决了这个问题:

关闭我的 wifi/以太网连接并打开。 我在终端输入:npm update 来更新 npm。 我尝试退出会话并重新登录

之后,我尝试了相同的 npm 命令,好在它成功了。我不确定它是否那么简单。

我正在使用 CENTOS 7

【讨论】:

【参考方案13】:

我只是想通了,至少在我的用例中是这样。

我收到了ECONNRESET。事实证明,我的客户端的设置方式非常迅速地通过 API 调用多次访问服务器——而且它只需要访问端点一次。

当我修复它时,错误消失了。

【讨论】:

【参考方案14】:

我遇到了同样的问题,似乎是 Node.js 版本的问题。

我安装了以前版本的 Node.js (10.14.2),使用 nvm 一切正常(允许您安装多个版本的 Node.js 并快速从一个版本切换到另一个版本)。

这不是一个“干净”的解决方案,但它可以暂时为您服务。

【讨论】:

【参考方案15】:

尝试将这些选项添加到 socket.io:

const options =  transports: ['websocket'], pingTimeout: 3000, pingInterval: 5000 ;

希望对你有帮助!

【讨论】:

【参考方案16】:

Node JS 套接字是非阻塞 io。考虑使用来自其他来源的非阻塞 io 连接。例如,如果您使用带有节点的阻塞 Java 套接字,它将仅工作几秒钟,之后将提供错误。通过实现非阻塞连接来缓解这种情况,即带有选择器的套接字通道。

【讨论】:

以上是关于如何在 Node.js 中调试错误 ECONNRESET?的主要内容,如果未能解决你的问题,请参考以下文章

调试 Node.js 应用程序时,WebStorm 在错误的文件上停止

如何启用调试 express.js/node.js 应用程序

node.js调试

如何调试Node.js应用程序?内置的

如何用最好的工具来调试node.js

调试 node.js 程序