0

在我的由 PM2 运行的 NodeJS 服务器中,我使用 npm 模块"ldap-authentication"通过 LAPD 服务对我的用户进行身份验证。

const { authenticate } = require('ldap-authentication');
...
try {
   const auth = await authenticate(options);
   return auth;
} catch(err){
   return err;
}

当凭据正常时,它工作正常。

当凭据错误时,函数会抛出一个可以被捕获并轻松处理的正确错误。

当没有连接并且出现“getaddrinfo ENOTFOUND”错误时,问题就出现了,

Error: getaddrinfo ENOTFOUND xxx.xxx.corp
at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:60:26)

因为代码崩溃而没有发现任何导致不可接受的问题的错误(尽管 PM2 重新启动了代码)。我需要处理可能断开的连接并避免服务器崩溃。

看起来不是从异步函数中捕获错误的问题,因为该函数的其他类型的错误被捕获。关注此链接似乎是此特定模块中此特定错误的问题。

有任何想法吗?

4

2 回答 2

1

不幸的是,这似乎是底层ldapjs库中的错误。ENOTFOUND需要在 中进行处理,但是Socket.on('error')直到调用之后才设置它,Socket.connect()因此在发生 DNS 错误时它不可用。

您可以在此处查看代码https://github.com/ldapjs/node-ldapjs/blob/master/lib/client/client.js#L827

if (server && server.secure) {
  socket = tls.connect(port, host, self.tlsOptions)
  socket.once('secureConnect', onConnect)
} else {
  socket = net.connect(port, host)
  socket.once('connect', onConnect)
}
socket.once('error', onResult)

要处理 DNS 错误,它需要如下所示

// reference to the socket
let socket;
if (server && server.secure) {
  // create TLS socket and connection handler
  socket = new tls.TLSSocket(self.tlsOptions);
  socket.once('secureConnect', onConnect)
} else {
  // create net socket and connection handler
  socket = new net.Socket();
  socket.once('connect', onConnect)
}
// set up error handler - including DNS 
socket.once('error', onResult)
// connect the socket after we have an error handler
socket.connect(port, host)

我还没有测试过,但有可能向您在这里使用的模块添加错误处理程序也可以工作 - https://github.com/shaozi/ldap-authentication/blob/master/index.js#L8

var client = ldap.createClient(ldapOpts)
client.on('error', (err) = { /* set up before connect */ });

除了提交 PR 来修复底层库之外,我最好的想法是在尝试连接之前使用包装器进行 DNS 查找 - https://nodejs.org/api/dns.html#dns_dns_lookup_hostname_options_callback

const dns = require('dns');

const auth = await new Promise((resolve, reject) => { 
  dns.lookup('xxx.xxx.corp', (err, address, family) => {
    // console.log('address: %j family: IPv%s', address, family));
    if (err) {
      return reject(err);
    }
    return resolve(authenticate(options));
  }
});
于 2020-10-09T17:10:48.260 回答
0

稍作修改以区分错误凭据的错误和调用函数中的通信中断情况。

如果错误抛出拒绝,如果凭据错误,则无需参数即可解决。

return new Promise((resolve, reject) => {

  dns.lookup('xxx.xxx.corp', async (err, address, family) => {

    if (err) {

      return reject(err);

    };

    try {

      const x = await(authenticate(options));

      return resolve(x);

    } catch(err){

      return resolve();

    }

  });

});
于 2020-10-13T15:51:07.183 回答