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


288

我正在使用Socket.io运行Express.js应用程序用于聊天Web应用程序,并且在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问题,而是对我执行的另一台服务器或MySQL / Redis连接的HTTP请求。问题是错误堆栈无法帮助我识别代码问题。这是日志输出:

    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] ] } }

在这里,我提供Flash套接字策略文件:

    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)

这可能是原因吗?


3
@GottZ也许可以帮助(告诉在节点js中工作的人)gist.github.com/samsonradu/1b0c6feb438f5a53e30e。我今天将部署socket.error处理程序,并通知您。
参孙

1
@Gottz socket.error句柄没有帮助,但是process.on('uncaughtException')捕获了错误。这是错误的console.log:{[错误:读取ECONNRESET]代码:'ECONNRESET',errno:'ECONNRESET',syscall:'read'}
Samson

1
ECONNRESET可能来自网络问题。如您所知,测试时不可能捕获所有异常。有些会显示在您的生产服务器上。您将必须使服务器稳定。您可以使用Redis作为存储来处理会话删除。即使您的节点服务器出现故障,它也可以使会话持续存在。
user568109 2013年

1
为什么这与会话删除有关?无论如何,它们都由Redis处理。
参孙

3
您至少有一个未设置处理程序的TCP套接字侦听。因此,现在该检查那个位置了:D
Moss 2013年

Answers:


252

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

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

但是,既然你也正在寻找一种方法来检查错误和潜在的调试问题,你应该看看如何调试插座挂断错误的NodeJS?这是在关系张贴在计算器到相似的问题。

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

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

干净正确的解决方案:从技术上讲,在节点中,每当您发出一个'error'事件而没有人监听它时,它将抛出。要使其不被抛出,请在其上放置一个侦听器并自己处理。这样,您可以记录错误的更多信息。

要为一组呼叫使用一个侦听器,您可以使用 ,也可以在运行时捕获其他错误。与代码的其他部分相比,确保与http(Server / Client)相关的每个异步操作都在不同的上下文中,该域将自动侦听error事件并将其传播到它自己的处理程序中。因此,您只听该处理程序并获取错误数据。您还可以免费获得更多信息。

编辑(2013-07-22)

正如我上面所写:

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

情况也可能是这样:在随机时间,另一侧过载,结果只是终止了连接。如果是这种情况,则取决于您所连接的对象。

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


它不必意味着“突然关闭”。通常是由于写入对等端已经正常关闭的连接而导致的。这将导致它发出RST。
罗恩侯爵

1
@EJP我写“突然”的原因很充分。错误(非警告)指出连接已被对等方重置。远程对等方强行关闭了现有连接。意外关闭会导致突然关闭!(这通常是由于远程计算机上的对等应用程序突然停止,计算机重新启动或对等应用程序在远程套接字上使用“硬关闭”而导致的。如果由于“保持活动”活动而导致连接断开,也可能导致此错误。在执行一个或多个操作时检测到故障…这些操作和后续操作将失败。)
e-sushi 2014年

2
当我从浏览器(Chrome)批量同时发送约100个API调用进行测试时,会引发此错误。我想Chrome一定会变得超负荷并杀死某些连接... @Samson-在自己的域中处理每个请求并在不重新启动服务器的情况下捕获域错误是怎么回事?
supershnee 2014年

2
@supershnee由于数据,应用程序和node.js本身处于未知状态,因此几乎应该始终在发生未捕获的异常后重新启动服务器。发生异常后继续操作会给您的数据带来风险。如果您想了解更多信息,请查看Process上的Node文档domains上的Node文档
c1moore

39

我用于提供Flash策略文件的一个简单的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)

2
代码有什么问题吗?写入之前是否应该检查套接字是否可写?
参孙

Doh,在我发布几乎相同的内容之前,没有看到您已经找到了解决方案:)不过,对于您的问题,即使您检查套接字是否可写,也可能不是在几秒钟后写入套接字的时候,仍然会引发错误,因此可以肯定的是这是“方法”。
Joachim Isaksson

好的,如果这样,有没有安全的出路?像错误处理程序中的socket.close()吗?因为我认为这些错误之后我的CPU负载正在增加(不确定)
Samson

2
我总是socket.destroy()在错误处理程序中进行确认。可悲的是,我找不到是否需要的文档,但是这样做并没有出错。
Joachim Isaksson

socket.destroy()挽救了我的一天,不管它能起作用!谢谢!
Firas Abd Alrahman '16

27

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

  • 净额:请勿压制ECONNRESET(Ben Noordhuis)

早期版本不会因客户端中断而出错。来自客户端的连接中断将在节点中引发错误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。东西,它仍然会给出错误。同样,我认为这是有意的,解决方案是处理代码中的错误。


3
谢谢,我自己钉了它!重要的是不要让错误传播到uncaughtException,因为这会使整个应用程序变得不稳定。例如,在捕获到10个ECONNRESET错误之后,服务器有时变得无响应(只是冻结并且没有处理任何连接)
Samson

还知道节点版本更改不再抑制错误,但是看到很多问题出现并解决了每个版本,我宁愿使用最新版本。我现在正在使用V0.10.13,顺便说一句
萨姆森

16

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


4
很奇怪,这个老问题应该在我期待的时候弹出一个新的答案-太好了,谢谢
分号

13

我遇到了同样的问题,但通过放置以下内容缓解了它:

server.timeout = 0;

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


5
这不是解决方案,而是一种快速修复程序,它可以在不引发错误的情况下中断事情。
Nishant Ghodke '18

9

另一种可能的情况(但很少见)可能是您具有服务器到服务器的通信并且设置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。如果您明确覆盖了该值,则只有这种情况(如您所说)。
朱斯

7

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

要重复,只需在代码中添加延迟即可:

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() { console.log("error"); });
    socket.write("<?xml version=\"1.0\"?>\n");
}

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

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


6

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

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


4

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

我的解决方案

对我来说,VirtualBox(对于Docker)是个问题。我在VM上配置了端口转发,并且错误仅在转发的端口上发生。

一般结论

以下观察结果可以为您节省我不得不投入的工作:

  • 对我来说,问题仅发生在一个端口上从本地主机到本地主机的连接上。->检查更改任何这些常数即可解决问题。
  • 对我来说,问题仅发生在我的机器上->让其他人尝试一下。
  • 对我来说,该问题仅在一段时间后发生,无法可靠地重现
  • 我的问题无法用任何节点或表达(调试)工具进行检查。->不要在此浪费时间

->弄清您的网络(设置)是否混乱,例如VM,防火墙等,这可能是问题的原因。


2

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

如上所述,ECONNRESET表示TCP会话突然关闭其连接结束。

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


这个对我
有用

2

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

  • 关闭我的wifi /以太网连接,然后再打开。
  • 我输入: npm update在终端中更新npm。
  • 我尝试从会话中注销并再次登录

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

我正在使用CENTOS 7


0

我遇到了同样的问题,看来Node.js版本就是问题所在。

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

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


0

我只是想出了这一点,至少在我的用例中。

我正在 ECONNRESET。事实证明,我的客户端的设置方式是通过API调用快速击中服务器很多次-只需击中端点一次。

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


-2

尝试将以下选项添加到socket.io:

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

我希望这能帮到您 !

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.