
本文介绍一种可靠方式,为 express 的所有异步路由处理器自动添加 try-catch 包装,避免因未处理 promise 拒绝(如 mongodb 报错)导致进程崩溃,并确保错误能正确传递至全局错误中间件。
Express 默认不会自动捕获异步函数中抛出的错误(例如 async 处理器内部 await 一个失败的 Promise),因为这类错误会以未处理的 Promise rejection形式存在,根本不会进入同步 try...catch 块——这正是你遇到“catch 不生效、应用直接崩溃”的根本原因。
你的 tryCatch 包装器逻辑方向正确,但当前实现存在关键缺陷:它同步调用了 func(req, res, next),而该函数返回的是一个 Promise;你并未 await 它,因此 Promise 内部的异常无法被同步 catch 捕获。
✅ 正确写法如下(支持 TypeScript 类型,兼容 Express 4.x+):
import { Request, Response, NextFunction } from 'express';
export const tryCatch = (
func: (req: Request, res: Response, next: NextFunction) => Promise
): ((req: Request, res: Response, next: NextFunction) => void) => {
return (req, res, next) => {
// 关键:必须 await 并 catch Promise rejection
func(req, res, next).catch(next);
};
}; ⚠️ 注意事项:
- func 必须是 async 函数(即返回 Promise),否则 .catch() 无意义;
- 不要手动调用 next(err) 在 catch 块里再做判断——直接 func(...).catch(next) 是最简洁、最健壮的方式,Express 会自动识别并交由后续错误中间件处理;
- 确保你已定义并注册了全局错误处理中间件(必须有 4 个参数),例如:
// 全局错误处理器(务必放在所有路由和普通中间件之后)
app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
console.error('Unhandled error:', err);
res.status(500).json({ success: false, message: 'Internal Server Error' });
});? 使用示例:
// routes/auth.ts
import { tryCatch } from '../utils/tryCatch';
export const login = tryCatch(async (req, res) => {
const user = await User.findOne({ email: req.body.email });
if (!user) throw new Error('User not found'); // ✅ 被自动捕获
const isValid = await bcrypt.compare(req.body.password, user.password);
if (!isValid) throw new Error('Invalid credentials');
res.json({ token: signToken(user) });
});? 进阶建议:
若项目中大量使用 async/await,还可封装成更通用的高阶函数(如支持返回值类型推导),或结合日志、错误分类(如 MongoError 判定后转为 409)、响应标准化等能力进一步增强鲁棒性。但核心原则不变:对 async 处理器,必须 .catch(next),而非仅包裹同步调用。










