
本文介绍如何通过高阶函数 trycatch 安全包装 express 异步路由处理器,解决 async/await 中未被捕获的 promise 拒绝导致进程崩溃的问题,并确保所有异步错误都能被全局错误处理中间件接管。
你遇到的问题非常典型:当前的 tryCatch 包装器虽然能同步调用 func(req, res, next),但它无法等待异步函数的执行结果。当传入的是 async (req, res, next) => { ... } 时,该函数会立即返回一个 Promise;而你的 try 块中只是调用了这个函数,并未 await 其返回的 Promise —— 因此内部 throw 或 Promise rejection(如 MongoDB 的 E11000 duplicate key 错误)不会触发 catch,而是成为「未处理的 Promise rejection」,最终导致 Node.js 进程崩溃或静默失败。
✅ 正确做法是:在包装器中 await 异步处理器的执行,并统一将同步异常与 Promise rejection 转发给 next():
// utils/tryCatch.ts
import { RequestHandler } from 'express';
export const tryCatch = (handler: RequestHandler): RequestHandler => {
return async (req, res, next) => {
try {
// ✅ 关键:await 确保 Promise rejection 被捕获
await handler(req, res, next);
} catch (err) {
// ⚠️ 注意:若 handler 内部已调用 next(err),此处可能重复触发
// 推荐 handler 内不手动调用 next(err),统一由 tryCatch 处理
next(err);
}
};
};使用方式如下(简洁、无冗余 try-catch):
// controllers/auth.ts
import { tryCatch } from '../utils/tryCatch';
export const login = tryCatch(async (req, res) => {
const { email, password } = req.body;
const user = await User.findOne({ email });
if (!user || !(await bcrypt.compare(password, user.password))) {
throw new Error('Invalid credentials'); // ✅ 自动被 tryCatch 捕获
}
res.json({ token: signToken(user) });
});? 重要注意事项:
- ❌ 不要在被包装的异步函数内调用 next(err) —— 否则 tryCatch 可能因 res 已发送而报错(如 Cannot set headers after they are sent);
- ✅ 必须在 Express 应用中注册全局错误处理中间件(4 参数签名),否则 next(err) 将无处可去:
// app.ts
app.use('/api/auth', authRouter);
// ✅ 全局错误处理器(必须放在所有路由之后)
app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
console.error('Unhandled error:', err);
res.status(500).json({
success: false,
message: 'Something went wrong',
...(process.env.NODE_ENV === 'development' && { stack: err.stack })
});
});
// ✅ 可选:处理未捕获的 Promise rejection(兜底防护)
process.on('unhandledRejection', (reason, promise) => {
console.error('Unhandled Rejection at:', promise, 'reason:', reason);
process.exit(1); // 或优雅降级
});? 总结:tryCatch 的本质是「Promise-aware 错误拦截器」。它不是替代 Express 错误处理机制,而是与其协同工作——将异步错误标准化为 next(err) 调用,交由 Express 的错误传播链统一调度。这一模式显著提升代码可维护性,是构建健壮 Express API 的推荐实践。










