Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/mercurial/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Node.js Express和async/await:我要用try/catch来包装这批货吗?_Node.js_Express_Async Await_Try Catch - Fatal编程技术网

Node.js Express和async/await:我要用try/catch来包装这批货吗?

Node.js Express和async/await:我要用try/catch来包装这批货吗?,node.js,express,async-await,try-catch,Node.js,Express,Async Await,Try Catch,我有以下代码: app.post('/routes/passwordReset/:userId', async (req, res, next) => { var userId = req.params.userId let record = (await vars.connection.queryP('SELECT * FROM contacts WHERE id = ?', userId))[0] if (!record) { res.status(404).s

我有以下代码:

app.post('/routes/passwordReset/:userId', async (req, res, next) => {
  var userId = req.params.userId

  let record = (await vars.connection.queryP('SELECT * FROM contacts WHERE id = ?', userId))[0]

  if (!record) {
    res.status(404).send('')
    return
  }

  // Calculate token and expiry, update database
  var token = require('crypto').randomBytes(48).toString('base64').replace(/[^a-zA-Z0-9]/g, '').substr(0, 28)
  var now = new Date()
  var inOneHour = new Date(now.getTime() + (1 * 1000 * 60 * 60))
  await vars.connection.queryP('UPDATE contacts SET recoverToken = ?, recoverTokenExpiry = ? WHERE id = ?', [ token, inOneHour, userId ])
  res.status(200).send('')
})
如果我创建了一个人为错误(例如,
recoverTokenExpiration
的字段人为地太短),我最终会得到:

[12:19:55.649][错误](节点:11919) 未处理的PromisejectionWarning:未处理的承诺拒绝 (拒绝id:4):错误:ER_DATA_过长:数据对列过长 第1行的“recoverToken”

我不知何故认为Express应该尝试/捕获中间件,并在抛出错误时调用
next(err)
。也许不是这样


那么,我是否应该用try/catch(e)包装每条路由,如果出现错误,则执行next(e)

Express对您没有任何帮助。这是非常赤裸裸的

您有两个选择:

  • 将所有内容包装在一个
    try catch
  • 编写自己的错误处理中间件,如文档所示
  • 调用
    next()
    req
    res
    传递到堆栈中的下一个中间件

    调用
    next(err)
    ,或者给它一个
    Exception
    对象,将调用堆栈中的任何错误中间件


    在自己的文件中定义错误处理程序:

    // error-middleware.js
    
    /**
     * Handler to catch `async` operation errors.
     * Reduces having to write `try-catch` all the time.
     */
    exports.catchErrors = action => (req, res, next) => action(req, res).catch(next)
    
    /**
     * Show useful information to client in development.
     */
    exports.devErrorHandler = (err, req, res, next) => {
      err.stack = err.stack || ''
      const status = err.status || 500
      const error = { message: err.message }
      res.status(status)
      res.json({ status, error })
    }
    
    然后将密码重置逻辑移出
    应用程序。post
    并进入其专用功能:

    // password-controller.js
    
    exports.resetPassword = async (req, res) => {
      // do work
      // ...
    }
    
    这使得编写单元测试变得更容易,并且可以清楚地分离关注点

    下一步创建密码重置路由:

    请注意,上面定义的控制器是在这里导入和使用的。此外,您还可以看到控制器操作
    resetPassword
    catchErrors
    包装。这避免了必须一直编写
    try catch
    ,任何错误都将被
    catchErrors
    中间件捕获

    最后,将其连接到主
    app.js
    文件中:

    // app.js
    
    const express = require('express')
    const { devErrorHandler } = require('./error-middleware')
    const passwordResetRoutes = require('./password-reset-routes.js')
    const app = express()
    
    app.use(devErrorHandler)
    app.use(passwordResetRoutes)
    
    module.exports = app
    

    当您使用wait关键字时,这意味着执行流不再是异步的,这就是它失败的原因,是的,每次都必须使用try-catch块。为了避免这种情况,您可以改为遵循异步流,分别使用then()和catch(),这样您可以执行以下操作:

    ...
    .then((status)=>{
      res.status(200).send('')
    })
    .catch((err)=>{
      next(err);
    });
    ...
    

    正如其他人所回应的,因为您使用的是wait,所以您可以将拒绝承诺处理为

    let record = await vars.connection.queryP('SELECT * FROM contacts WHERE id = ?', userId))[0].then(function () {
         console.log("Promise Resolved");
    }).catch((error)=>{
        console.log("Promise rejected")
    })
    

    请参阅此处了解中间件try/catch,例如
    app.use(函数(err,req,res,next){console.error(err.stack)res.status(500.send('something break!'))错误中间件没有被调用,因为错误没有被捕获…我不确定我是否理解“选项2”:我已经有了错误处理中间件。然而,除非我在那里尝试捕捉,否则它不会被调用。所以我假设我必须同时拥有(1)和(2),这样我就可以
    尝试{…}catch(e){next(err)}
    了,对吗?你可以这样做,或者将函数包装在
    catch
    中,因为
    异步
    函数总是返回
    承诺。请参阅更新的答案和示例。我理解,但承诺是一个(重要的)ES标准,我不知道在没有
    then()
    catch
    方法的情况下是否可以使用它们。您可以尝试其他方法,比如Observables(还不是ES标准),或者停止使用JS/Node,我认为这不是一个选项
    let record = await vars.connection.queryP('SELECT * FROM contacts WHERE id = ?', userId))[0].then(function () {
         console.log("Promise Resolved");
    }).catch((error)=>{
        console.log("Promise rejected")
    })