- Published on
Express 处理同步/异步错误 | asyncHandler | errorHandler
- Authors
- Name
- Shelton Ma
处理同步和异步错误
在 Express 中,你可以在 controller 层抛出异常,而不需要在每个 server 层使用 try-catch 来捕获异常.最佳实践是通过全局错误处理中间件来统一处理异常.这样可以更简洁地管理错误逻辑,避免冗余的 try-catch 代码
实现思路: Controller 层抛出异常, 使用 asyncHandler 中间件封装异步路由
1. 错误处理中间件
// src/middlewares/error.middleware.ts
import { NextFunction, Request, Response } from "express";
export const errorHandler = (
err: Error & { statusCode?: number },
req: Request,
res: Response,
next: NextFunction
) => {
const statusCode = err.statusCode ?? 500;
// 响应内容,避免暴露敏感信息
const errorMessage =
process.env.NODE_ENV === "production"
? "Internal Server Error"
: err.message || "Unknown error";
console.error({
message: err.message || "Unknown error",
stack: err.stack,
});
res.status(statusCode).json({
success: false,
message: errorMessage,
});
};
2. 异步/同步错误捕获器
// src/utils/async-handler.ts
import { NextFunction, Request, Response } from "express";
/**
* @description 异步/同步错误捕获器
* @param fn 控制器/服务函数
*/
export const asyncHandler = (
fn: (req: Request, res: Response, next: NextFunction) => Promise<void> | void
) => {
return (req: Request, res: Response, next: NextFunction) => {
try {
const result = fn(req, res, next);
// 检查是否为 Promise,处理异步异常
if (result && result instanceof Promise) {
result.catch((error) => {
console.error(`[asyncHandler Error] ${error.message}`);
next(error); // 将异常传递给全局错误处理中间件
});
}
} catch (error) {
console.error(`[asyncHandler Error] ${error.message}`);
next(error); // 处理同步异常
}
};
};
3. Controller直接抛出异常, 在Router中无需 try-catch
// /src/controllers/user.controller.ts
const error = new Error("User not found");
(error as any).statusCode = 404;
throw error;
// /src/routes/user.route.ts
import express from "express";
import { asyncHandler } from "../utils/async-handler";
import { getUser } from "../controllers/user-controller";
const router = express.Router();
router.get("/user/:id", asyncHandler(getUser)); // 不需要 try-catch
export default router;