You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决Express错误处理中间件未被调用的问题

Express错误处理中间件无法捕获异步路由中的错误

我知道这个问题已经被提过很多次,也试过其他解决方案,现在请求帮忙调试。我配置了独立的errorHandler中间件,但抛出Error时Express没能捕获——终端能看到错误信息,但中间件完全没触发。

相关代码

error-handler.ts

import express, { Request, Response, NextFunction } from "express";

export const errorHandler = (
  err: Error, 
  req: express.Request, 
  res: express.Response, 
  next: express.NextFunction
) => {
  console.log('Something went wrong');
  res.status(400).send({
    message: err.message
  });
}

index.ts

import express, { Request, Response, NextFunction } from 'express';
import { json } from 'body-parser';
import { currentUserRouter } from './routes/current-user';
import { signinRouter } from './routes/signin';
import { signoutRouter } from './routes/signout';
import { signupRouter } from './routes/singup';
import { errorHandler } from './middlewares/error-handlers';

const app = express();
app.use(json());

app.use(currentUserRouter);
app.use(signinRouter);
app.use(signoutRouter);
app.use(signupRouter);

app.use(errorHandler);

app.listen(3000, () => {
  console.log('Listening on port 3000!!!');
})

signup.ts

import express, { Request, Response } from "express";
const router = express.Router();
import { body, validationResult } from "express-validator";

const bodyValidation = [
  body('email')
    .isEmail()
    .withMessage('Email must be valid'),
  body('password')
    .trim()
    .isLength({ min: 4, max: 20})
    .withMessage('Password must be between 4 and 20 characters')
];

router.post('/api/users/signup', bodyValidation, async (req: Request, res: Response) => {
  const errors = validationResult(req);
  if(!errors.isEmpty()) {
    throw new Error('Invalid email or password');
  }
  
  console.log('Creating a user...');

  res.send({});
});

export { router as signupRouter }

问题原因

核心问题在于你的路由处理函数是异步函数:Express 默认不会自动捕获异步函数中抛出的错误。异步函数抛出的错误会被包装成 Promise 的 reject 状态,而 Express 本身不会处理未捕获的 Promise 拒绝,所以错误只会在终端打印,不会触发你的errorHandler中间件。

解决方案

方案1:用 try/catch 捕获错误并传递给 next

修改 signup.ts 的路由处理函数,添加 try/catch 块,在捕获错误后调用next(err)将错误传递给错误处理中间件:

import express, { Request, Response, NextFunction } from "express"; // 别忘了导入NextFunction
const router = express.Router();
import { body, validationResult } from "express-validator";

const bodyValidation = [
  body('email')
    .isEmail()
    .withMessage('Email must be valid'),
  body('password')
    .trim()
    .isLength({ min: 4, max: 20})
    .withMessage('Password must be between 4 and 20 characters')
];

router.post('/api/users/signup', bodyValidation, async (req: Request, res: Response, next: NextFunction) => {
  try {
    const errors = validationResult(req);
    if(!errors.isEmpty()) {
      throw new Error('Invalid email or password');
    }
    
    console.log('Creating a user...');
    res.send({});
  } catch (err) {
    next(err); // 把错误交给错误处理中间件
  }
});

export { router as signupRouter }

方案2:直接用 express-validator 返回错误(更简便)

既然已经用了 express-validator,没必要手动抛出错误,可以直接返回格式化的错误响应:

router.post('/api/users/signup', bodyValidation, async (req: Request, res: Response) => {
  const errors = validationResult(req);
  if(!errors.isEmpty()) {
    // 直接返回错误响应,无需经过全局错误中间件
    return res.status(400).send({ errors: errors.array() });
  }
  
  console.log('Creating a user...');
  res.send({});
});

方案3:封装异步路由包装器(全局复用)

如果有大量异步路由,可以写一个通用的包装函数,自动捕获异步错误并传递给 next:

// 新建一个async-wrapper.ts文件
import { Request, Response, NextFunction } from "express";

export const asyncWrapper = (fn: (req: Request, res: Response, next: NextFunction) => Promise<any>) => {
  return (req: Request, res: Response, next: NextFunction) => {
    fn(req, res, next).catch(next);
  };
};

然后在 signup.ts 中使用:

import { asyncWrapper } from '../middlewares/async-wrapper';

// ... 其他代码不变

router.post('/api/users/signup', bodyValidation, asyncWrapper(async (req: Request, res: Response) => {
  const errors = validationResult(req);
  if(!errors.isEmpty()) {
    throw new Error('Invalid email or password');
  }
  
  console.log('Creating a user...');
  res.send({});
}));

内容的提问来源于stack exchange,提问作者jkalandarov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 01:10:25