Express 异步错误

534 阅读2分钟

express 中的错误捕获

我们使用 express 时我们都会编写一个中间件来统一处理中间件处理函数中发生的错误 通常我们会将这个中间件放在最后,这样之前发生的所有错误最后都会被错误中间件捕获处理

eg:

const express = require("express");
// require("express-async-errors");
const app = express();

// 抛出一个同步错误
function syncErr() {
  throw new Error("同步错误");
}
// 抛出一个异步错误
function asyncErr() {
  return Promise.reject(new Error("异步错误"));
}

app.get("/test/sync", (req, res, next) => {
  syncErr();
});

app.get("/test/async", async (req, res, next) => {
  try {
    await asyncErr();
  } catch (err) {
    next(err);
  }
});

// 错误中间件
app.use((err, req, res, next) => {
  if (err) {
    res.status(500).send(err.message);
    return;
  }
  next();
});

app.listen(6666, () => {
  console.log("server listen 6666");
});

但当express遇见异步错误时问题发生了

  • 当我们访问 "/test/sync" 时会抛出一个同步错误,这个错误能够被错误中间件正常捕获并处理

  • 当我们访问"/test/async" 时会有一个异步的错误,在不使用try/catch的情况下程序会直接报错,并不会被错误中间捕获处理,只有在catch到错误并通过 next 传递给下一个中间件,错误中间件才能够捕获这个错误并进行处理

    (express 是较早出一个框架,主要使用 es5 语法采用的是 callback 回调方式,具体原因可自行观看源码)

解决方案

由于数据库操作中会有大量的异步操作,每次异步操作都需要写 try/catch 来讲错误抛出,显然过于繁琐,我们可以使用异步处理函数来帮助我们进行 try/catch 的操作

// asyncHandler接受一个函数作为参数,最后返回一个中间件处理函数
function asyncHandler(fn) {
  return async (req, res, next) => {
    try {
      await fn(req, res, next);
    } catch (err) {
      next(err);
    }
  };
}

// 使用方法
app.get(
  "/test",
  asyncHandler(async (req, res, next) => {
    ....
    // 可以随意进行异步操作,最后都能被编写的错误中间件捕获
  })
);

express-async-errors 插件

每次编写中间件处理函数时都需要包裹 asyncHandler 高阶函数,用起来也不够方便 express-async-errors 插件很好的解决了这个问题 只需要将该插件引入即可随意抛出错误,最后都能够被错误中间件所捕获

like:

const express = require("express");
// 只需要直接引入即可
require("express-async-errors");
const app = express();

function asyncErr() {
  return Promise.reject(new Error("异步错误"));
}

app.get("/test/async", async (req, res, next) => {
  // 引入后这样也会被错误中间件捕获
  await asyncErr();
});