简体   繁体   English

ExpressJS 中间件中的错误处理,next() 与 throw

[英]Error handling in ExpressJS middlewares, next() vs throw

I'm trying to understand handling errors in express.我试图了解快递中的处理错误。 TrustIP function is a middleware, which pass the error by calling next(new Error('err')) , but is also possible to do this with throw new Error . TrustIP function 是一个中间件,它通过调用next(new Error('err'))传递错误,但也可以通过throw new Error来传递错误。 Both seems to work, what's the correct way to do this and why?两者似乎都有效,正确的方法是什么,为什么? I'm still learning.我还在学习。 Thanks for your time.谢谢你的时间。

function trustIP(req, res, next) {
  const trustedIPs = ['**.**.**.**']
  let requestIP = req.headers['x-forwarded-for'] || req.socket.remoteAddress
  if (requestIP.substr(0, 7) === '::ffff:') {
    requestIP = requestIP.substr(7)
  }
  if (trustedIPs.indexOf(requestIP) >= 0) {
    next()
  } else {
    next(new Error(`Not trusted IP: ${requestIP} tryed to connect`))
    // throw new Error ???
  }
}
app.use('/', trustIP, navRoutes)
app.use(errorHandler)
app.listen(process.env.PORT, () => console.log(`Server on port: ${process.env.PORT}`))
const errorHandler = (err, req, res, next) => {
  console.error('error handler:', err.stack)
  res.status(500).send(err.message)
}

Per the docs , they basically do the same thing.根据文档,他们基本上做同样的事情。 However, in an asynchronous (function invoked in handler with callback in this context) function (eg fs.readFile ) you will need to use the callback and pass your error inside.但是,在异步(在此上下文中使用回调在处理程序中调用的函数)function(例如fs.readFile )中,您将需要使用回调并将错误传递给内部。

// synchronous, just throw
app.get('/', (req, res) => {
  throw new Error('BROKEN') // Express will catch this on its own.
})

// asynchronous, pass to callback
app.get('/', (req, res, next) => {
  fs.readFile('/file-does-not-exist', (err, data) => {
    if (err) {
      next(err) // Pass errors to Express.
    } else {
      res.send(data)
    }
  })
})

I haven't tested this myself, but I'm pretty sure this is because if no error is actually thown and the error is only visible via the parameter of the callback (of say fs.readFile ), no response will ever be sent to the client and they will wait for a response forever.我自己还没有测试过,但我很确定这是因为如果没有实际抛出错误并且错误仅通过回调参数(比如fs.readFile )可见,则永远不会发送任何响应客户和他们将永远等待响应。

In your trustIp function, next(new Error('err')) and throw new Error('err') would do exactly the same thing.在你的trustIp function 中, next(new Error('err'))throw new Error('err')会做同样的事情。

You can prove this by putting a breakpoint in your trustIp function and examining the code in express that calls it.您可以通过在trustIp function 中放置一个断点并检查调用它的 express 中的代码来证明这一点。 This is what you will find there: 是你会在那里找到的:

try {
  fn(req, res, next);
} catch (err) {
  next(err);
}

If your function throws an error, express simply catches it and calls the next function.如果您的 function 抛出错误,express 会简单地捕获它并调用next function。

But it's important to understand that the situation becomes different if you make trustIp into an async function. In that case, it's no longer a function that throws an error, but rather a function which returns a promise which will reject.但重要的是要了解,如果将trustIp为异步 function,情况就会有所不同。在这种情况下,抛出错误的不再是 function,而是返回将拒绝的 promise 的 function。 That's a different thing, and express (version 4) does not know how to handle it.那是另一回事,express(版本 4)不知道如何处理它。 That's why calling next(err) in your code is generally a good habit to get into when using express.这就是为什么在代码中调用next(err)通常是使用 express 时养成的好习惯。

So, in general, the difference between handling an error and rethrowing the error is in the question of whose responsibility is it to handle it.因此,一般来说,处理错误和重新抛出错误之间的区别在于由谁负责处理错误的问题。

Case 1) Imagine you create an API where you enter a phone number into an input field.案例 1) 假设您创建了一个 API,您在其中将电话号码输入到输入字段中。 The method does not take letters.该方法不接受字母。 It only takes numbers.它只需要数字。 At this time, you would assume that the programmer who is using your code needs to pass the error back to the user and tell them that they can only enter numbers.这时,你会假设正在使用你的代码的程序员需要将错误返回给用户并告诉他们只能输入数字。 The user though enters letters.用户虽然输入了字母。 At this point, you would throw the error back to the person who calls it so they can tell the user to correct it.此时,您会将错误返回给调用它的人,以便他们可以告诉用户更正它。

Case 2) An error is handled when something happens due to something that is out of the control of the person who calls it, then the code handles the error by logging it and maybe bringing up a page.情况 2) 当某些事情由于调用者无法控制的事情而发生时,错误被处理,然后代码通过记录它并可能调出一个页面来处理错误。 This might happen if a server is down, and your call depends on whether a server is up.如果服务器关闭,则可能会发生这种情况,而您的调用取决于服务器是否启动。 At that point, you handle the error with a meaningful error code telling the user roughly what is going on.那时,您使用有意义的错误代码来处理错误,告诉用户大致发生了什么。 There is nothing the caller of your method can do to resolve it.您的方法的调用者无法解决它。 When you handle an error, put as much information in the logs as possible for the person who will debug this so they can figure out why the problem occurred.当您处理错误时,请在日志中尽可能多地为调试人员提供更多信息,以便他们找出问题发生的原因。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM