Nodejs Socket 挂断和 ECONNRESET - 从 Meteor 到 Node js 服务器的 HTTP 发布请求

Posted

技术标签:

【中文标题】Nodejs Socket 挂断和 ECONNRESET - 从 Meteor 到 Node js 服务器的 HTTP 发布请求【英文标题】:Nodejs Socket hang up & ECONNRESET - HTTP post request from Meteor to Node js server 【发布时间】:2017-05-05 15:31:32 【问题描述】:

我正在使用节点服务器来处理我的所有推送通知服务,例如 gcm 和 apn。

我有 2 台不同的服务器。一个运行 Meteor,另一个运行 Node.JS 来处理推送通知。 (两者都是不同的服务器)

我的主应用在 Meteor 服务器上运行。

我向 node.js 服务器发出 HTTP 发布请求以发送我的通知。

通常它工作正常,但有时在 Meteor 服务器上,每当我调用 node.js 服务器时都会收到此错误:

socket hang up\n    at Object.Future.wait (/home/myPc/.meteor/packages/meteor-tool/.1.1.10.ki0ccv++os.linux.x86_64+web.browser+web.cordova/mt-os.linux.x86_64/dev_bundle/server-lib/node_modules/fibers/future.js:398:15)\n    at Object.<anonymous> (packages/meteor/helpers.js:119:1)\n    at Object.HTTP.call (packages/meteorhacks_kadira/lib/hijack/http.js:10:1)\n    at Object.sendPushNotificationsMeteorServer (server/pushNotifications.js:249:1)\n    at server/classes/pushNotifications.js:244:1\n    at [object Object]._.extend.withValue (packages/meteor/dynamics_nodejs.js:56:1)\n    at packages/meteor/timers.js:6:1\n    at runWithEnvironment (packages/meteor/dynamics_nodejs.js:110:1)\n    - - - - -\n    at createHangUpError (http.js:1473:15)\n    at Socket.socketOnEnd [as onend] (http.js:1569:23)\n    at Socket.g (events.js:180:16)\n    at Socket.emit (events.js:117:20)\n    at _stream_readable.js:944:16\n    at process._tickCallback (node.js:448:13)',
details:  [Error: socket hang up] stack: [Getter] ,
data:  [Error: socket hang up] stack: [Getter] ,
user: null,
userId: null,
toString: [Function] ,
user: null,
userId: null,
toString: [Function] 

错误:读取 ECONNRESET 在 Object.Future.wait (/home/mbm/.meteor/packages/meteor-tool/.1.1.10.12ml1tp++os.linux.x86_64+web.browser+web.cordova/mt-os.linux.x86_64/ dev_bundle/server-lib/node_modules/fibers/future.js:398:15) 在 Object.call (packages/meteor/helpers.js:119:1) 在 Object.sendHttpCall (server/pushNotifications.js:249:1) 在服务器/pushNotifications.js:244:1 在 [object Object]._.extend.withValue (packages/meteor/dynamics_nodejs.js:56:1) 在包/流星/timers.js:6:1 在 runWithEnvironment (packages/meteor/dynamics_nodejs.js:110:1) - - - - - 在 errnoException (net.js:905:11) 在 TCP.onread (net.js:559:19)

这是我的 Node.JS 服务器代码:

realFs                = require('fs');
var gracefulFs        = require('graceful-fs');
gracefulFs.gracefulify(realFs);

var http              = require('http');
var express           = require('express');
var app               = express();

var path              = require("path");

configClass           = require('./classes/config.js').configClass;
helperClass           = require('./classes/helper.js').helperClass;
pushNotificationClass = require('./classes/pushNotification.js').pushNotificationClass;

var hostname          = 'http://localhost'; 
var port              = 6000;

var bodyParser        = require('body-parser');

nodeGcm               = require('node-gcm');
apn                   = require('apn');
apnService            = new apn.Connection(helperClass.getAPNOptions());

// -- BODY PARSER -- //
app.use(bodyParser.json(limit: '50mb'));
app.use(bodyParser.urlencoded(limit: '50mb', extended: true));

process.on('uncaughtException', function (err) 

  console.error(err);
  console.log("Node NOT Exiting...");
);

// All post requests
app.post('/', function(req, res)

  try 

    var response = JSON.parse(req.body.pushNotificationApiParams);
    var callType = req.body.callType;

    switch (callType) 
        case 'systemPushNotifications':
            return pushNotificationClass.sendPushNotificationsV2(response);
        break;
     
  
  catch(e)

    console.dir(e.stack);
    realFs.appendFile('errorLogs/'+helperClass.getCurrentDateFormated()+'.log', helperClass.formatLog('Exception in main Post Method  : '+e.stack) , function (err) 
      if (err) throw err;
    );
  

  res.send("OK");
);



app.listen(port, function () 
  console.log('Listening at '+hostname+':'+port);
);

这是我来自 Meteor 端的代码,我在其中向节点 js 服务器发出 HTTP 发布请求:

var headers = 
   'Content-Type' : 'application/x-www-form-urlencoded'
;

var postFields = 
   callType : 'systemPushNotifications',
   pushNotificationApiParams  : JSON.stringify(pushNotificationApiParams)   // contains push notifications data                 
;

HTTP.call("POST", 'http://localhost:6000',  params:postFields, headers:headers );

谁能指引我正确的方向?此外,我也非常希望了解一些好的做法。

还有

我还面临一个问题。我的 node.js 服务器在 24 小时后退出。我不知道为什么会这样。它在终端控制台中退出,没有任何错误或异常。我每次都必须重新启动它。

【问题讨论】:

两台服务器是否在同一台机器上? @jannis 不,它们是不同的服务器 您应该考虑网络问题(介于两者之间的问题 - 例如网关/代理过载 - 重置连接)。我会在双方都设置 tcp 监控并尝试重现该问题。然后,当它发生时,我会检查日志以查看是否真的是 nodejs 服务器方破坏了连接。这将告诉您进一步查看的位置 - 网络或服务器本身。我会在网络上打赌,因为正如你所说,这是非常随机的。 【参考方案1】:

考虑到ECONNRESET错误通常发生在TCP connection的*另一端突然关闭时。

如果您的应用程序 这可能是由于服务器的 overloading 并简单地终止连接作为返回,它以类似的方式阻止与您的meteor server 的连接

要获取有关此thread 中提到的错误的更多信息。 要处理错误,您必须使用 event listener 来显示它的完整 stack traces

正如Farid Nouri Neshat在此线程中提到的那样

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

但由于该域已被弃用,您应该使用docs 中提到的集群,它使用server.listen(message)server.listen(handle)

或者您也可以使用NODE_DEBUG=net 或使用strace

更新

对于服务器断开,我认为错误可能在于您处理bodyparser。对于 json 文件错误未被捕获

在未捕获的异常之后节点的默认操作是退出(崩溃)进程。

可以通过以下方式处理 json 文件的 bodyparser。

var parseJson = bodyPaser.json();

app.use(function (req, res, next) 
    req.getBody = function (callback) 
        parseJson(req, res,function (err) 
          callback(err, req.body);
        );
    ;
    next();
); 

引用自 GITHUB 公开问题的here

更新 2

基本上socket hangup表示socket没有在指定时间段内结束连接

根据source,你可以看到它发生如果服务器从不发送响应

.这个错误应该被任何一方捕获和处理

正在重试请求。 稍后通过设置更多time period 或将res.end() 放在函数的末尾 来结束连接。 或者您可以将[http.get()][8]get 请求一起使用,这将自动调用req.end() 函数

希望对你有所帮助!干杯!

【讨论】:

我还面临一个问题。我的 nodejs 服务器在 24 小时后退出。我不知道为什么会这样。它在终端控制台中没有任何错误或异常退出。 请说明您使用的是哪个平台,以及任何其他可能需要的东西,我会尝试调查一下 两台服务器都托管在 Linux 操作系统上。 NodeJs 服务器只是处理推送通知。让我困惑的代码是 res.end('thanks');部分。我假设我的响应有时没有返回,因为这完全是一个异步操作,所以它有时可能不会返回确认,或者确认有时会延迟。这就是我的感觉 我正在设置 'Content-Type' : 'application/x-www-form-urlencoded' 并且我还在 HTTP 请求调用的参数中发送数据。这样做对吗? 我对@9​​87654345@ 并不太喜欢 pro,但我可以告诉你一件事,你需要向它提供 callback,因为请求是asynchronous,格式为Meteor.http.call("GET",url,function(error,answer) console.log(anwer.answer1); );,并获取错误日志。 其他功能保持不变,您可以将数据附加到它,如 json.【参考方案2】:

好的,我自己在这里发现了问题。它在节点服务器代码中。我将 return 放在 switch 语句中,这不是快速返回响应的有效方式,所以我只是从以下位置删除了 return:

之前:

switch (callType) 
   case 'systemPushNotifications':
      return pushNotificationClass.sendPushNotificationsV2(response);
   break;

现在:

switch (callType) 
   case 'systemPushNotifications':
      pushNotificationClass.sendPushNotificationsV2(response);
   break;

上面的return是终止之前的代码:res.send("OK");

【讨论】:

这甚至没有接近您建议的问题的解决方案,问题仍然存在,但我认为 @Pritish Vaidya 方法可以帮助其他有同样问题的人

以上是关于Nodejs Socket 挂断和 ECONNRESET - 从 Meteor 到 Node js 服务器的 HTTP 发布请求的主要内容,如果未能解决你的问题,请参考以下文章

NodeJS - “套接字挂断”实际上是啥意思?

邮递员:socket挂断

nodejs http请求套接字挂断

nodejs https错误:套接字挂断了本地主机

角度万能 | firebase 管理员 | code: 'app/invalid-credential' |socket 挂断

多个 API 调用的 Node Js 中的套接字挂断错误