乐趣区

关于express:express中异步函数异常捕获

express 中时应用 Async/await 编写异步代码时,每个 async 函数都要包裹在 try/catch 中,代码量多了看着冗余不优雅,express又不像 koa 的异步机制能够订阅全局的 error 事件,为了解决这个问题,须要写个捕捉异步函数异样的中间件。

uncaughtException

开始能想到的必定是 try/catch 了,然而也想过是否应用 nodejs 提供的 uncaughtException 事件,在全局捕捉异样,例如上面的代码:

process.on("uncaughtException", (err) => console.log("uncaught Exception"));

const asyncError=()=>{throw new Error("some Error");
}

asyncError();

asyncError办法外面抛出的异样会被 uncaughtException订阅,然而在异步函数中,并没走到 uncaughtException,还是会抛出异样:

process.on("uncaughtException", (err) => console.log("uncaught Exception"));

const asyncError=()=>{throw new Error("some Error");
}

(async ()=>{
    // 抛出异样
    asyncError();})()

而且 Promise.reject 也没走到 uncaughtException 外面:

const asyncError=()=>{return Promise.reject("some error")
}

(async ()=>{
    // 抛出异样
    await asyncError();})()

所以在 express 中应用 nodejs 提供的 uncaughtException 解决异步谬误不太适合,一方面没法捕捉和定位上下文谬误,另一方面也没法将谬误异样提供给中间件函数解决

解决思路

要解决 express 中的异步函数谬误,最好的办法当然是编写解决异样的中间件了,try/catch开路,包裹中间件办法,catch到的异样间接交给 next 函数解决,代码如下:

 const asyncHandler = fn =>{return (req,res,next)=>{
        try{fn(req,res,next)
        }catch(next)
    }
}
module.exports = asyncHandler;

接下来,在异步函数中引入中间件解决:

app.use(asyncHandler(async(req, res, next) => {await authenticate(req);
    next();}));

app.get('/async', asyncHandler(async(req, res) => {const result = await request('http://example.com');
    res.end(result);
}));

应用 asyncHandler 办法包裹的 async/await 函数,如果呈现谬误就会被 Error-handling 中间件捕捉了

然而每次用到异步函数的时候都要包裹 asyncHandler 办法,真正用起来也不是很爽,这里举荐应用 express-async-errors 中间件,其原理是将 express 外面的两头全副包裹上一层 asyncHandler 办法,让谬误异样无所遁形,全副跑到 Error-handling 中间件。

前提是引入 express 后,先引入 express-async-errors 办法:

const express = require('express');
require('express-async-errors');
const User = require('./models/user');
const app = express();

app.get('/users', async (req, res) => {const users = await User.findAll();
  res.send(users);
});

接下来的在异步函数中,就不必都包裹上 try/catch 了,有谬误提前throw Error,写起代码来美滋滋:

app.use(async (req, res) => {const user = await User.findByToken(req.get('authorization'));

  if (!user) throw Error("access denied");
});

app.use((err, req, res, next) => {if (err.message === 'access denied') {res.status(403);
    res.json({error: err.message});
  }

  next(err);
});~~~~

参考链接:
Using Async/await in Express
Handling errors in express async middleware

退出移动版