【问题标题】:Why would a NodeJS/restify server *rarely* report EPERM on accept?为什么 NodeJS/restify 服务器*很少*在接受时报告 EPERM?
【发布时间】:2016-07-12 05:49:44
【问题描述】:

我正在 NodeJS 中运行一个 restify 服务器。在极少数情况下,大约 0.05% 的 HTTPS 请求会导致 net.js 报告以下错误:

Error: accept EPERM
    at exports._errnoException (util.js:742:11)
    at TCP.onconnection (net.js:1280:24)

HTTP 请求没有什么特别之处。在报告此错误之前,服务器可能已经服务了数千个请求,甚至响应了数十个相同的请求。我找不到任何关于为什么服务器可能会为已成功接受连接数小时的套接字生成 EPERM 错误的任何信息。

顺便说一句,这个错误发生在我们源代码的任何执行上下文之外。因此,EPERM 并不是关于我们的代码访问文件或执行其他一些系统调用。当新请求到达并且在我们的代码被调用之前,EPERM 正在 NodeJS TCP 代码的深处发生。

起初,当错误发生时,它会导致 NodeJS 终止。然后我添加了代码来捕获应用程序级异常:

process.on("uncaughtException", onUncaughtException );

但是由于我不知道为什么会发生这个错误,所以完全不清楚恢复过程是什么。

不确定是否重要,但这里是与启动 restify 服务相关的大部分代码:

var restify    = require("restify");
// skipping some other init code
// configuration data is read from a JSON file
var serverOptions = {
   name: configuration.server.name,
   version: configuration.server.version,
   formatters: {
      "application/json": jsonResponseFormatter,
      "text/html": textResponseFormatter
   },
   serverOptions.key: fs.readFileSync(configuration.server.sslKey),
   serverOptions.cert: fs.readFileSync(configuration.server.sslCert)
}
var server = restify.createServer( serverOptions );
// skipping middleware inits and URL registrations
server.listen(
     configuration.server.port, // using HTTPS 443
     configuration.server.serverip );

顺便说一句,我们正在运行旧版本的 NodeJS:v0.11.13。我的长期计划是升级到最新的稳定版本,但我们可能要几个月才能更新。

【问题讨论】:

  • 当我让 Nodemon 读取包含它无法处理的文件的文件夹时,我遇到了 EPERM 错误。您最近是否将任何文件或文件夹添加到您的主服务器文件夹?
  • @WouldBe 否,此 EPERM 错误与任何类型的文件系统访问无关。当 HTTP 请求传入时,TCP/IP 套接字上报告错误。

标签: javascript node.js http error-handling


【解决方案1】:

让我把我的解决方案留在这里,以防其他人将来遇到同样的问题。

从技术上讲,我没有发现为什么会发生此错误,但我确实找到了如何成功处理错误情况:陷阱和释放。该错误必须在应用程序级别捕获,因为它是在我的源代码的任何 try-catch 上下文之外的 net.js 深处生成的。因此,如果我不捕获它,那么它将使我的应用程序崩溃。但是该错误不是致命的,并且似乎可以安全地忽略它。在测试中,即使发生此错误,套接字仍继续接收新连接。

process.on("uncaughtException", onUncaughtException );
function onUncaughtException(error) {
  // put some code here to log the error occurrence, then ...
  if( error.code==="EPERM" && error.syscall==="accept" ) {
     // non-fatal error: do nothing; just ignore this error
  }
  else {
    // handle other application errors here
  }
}

因此,虽然了解为什么服务器套接字可能偶尔会出现 EPERM 错误可能仍然很有趣,但现在我很满意知道在错误发生时处理错误的正确方法。p>

【讨论】:

    【解决方案2】:
    $ man 2 accept
    ...
    In addition, Linux accept() may fail if:
    
    EPERM  Firewall rules forbid connection.
    

    老实说,我不完全确定哪种类型的防火墙规则会导致此错误,我能想到的只是您可能有一个规则允许来自特定客户端的传入连接但不允许传出数据到该客户端的IP/网络/端口/...

    【讨论】:

    • 感谢您的回复,罗伯特。我将不得不调查这个想法。我希望我们的防火墙配置不会限制此端口上的连接,但我没有检查它,所以它是可能的。
    • @LeeJenkins 这可能有点晦涩,因为它只是偶尔触发。我认为这与正在连接的客户端的源地址有关(换句话说,对于您的服务器客户端的流量)。如果您记录下它发生的场合,这也可能会有所帮助,最好在旁边附上客户信息。
    猜你喜欢
    • 2014-08-22
    • 2014-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-14
    • 1970-01-01
    • 2014-09-15
    • 1970-01-01
    相关资源
    最近更新 更多