Express错误处理中间件未触发致服务崩溃问题求助
问题原因
你的路由处理器是async函数,内部抛出的错误会转化为未处理的Promise拒绝,Express无法自动将这类错误传递给自定义错误处理中间件,最终导致服务器崩溃。
解决方案
方案一:手动捕获错误并传递给next
修改路由处理器,添加next参数,用try/catch捕获错误后传递给错误中间件:
import express, { Request, Response, NextFunction } from "express"; import { body, validationResult } from "express-validator"; const router = express.Router(); router.post( "/lead", [ body("email").isEmail().withMessage("Email must be valid"), body("name").notEmpty().withMessage("A name has to be provided"), ], async (req: Request, res: Response, next: NextFunction) => { try { const errors = validationResult(req); if (!errors.isEmpty()) { throw new Error("Invalid Email"); } const { email, name } = req.body; console.log("Creating a user..."); res.send({}); } catch (err) { next(err); // 将错误传递给自定义错误处理中间件 } } ); export { router as leadRouter };
方案二:封装通用async错误处理包装函数
避免每个async路由都重复写try/catch,可以定义一个通用包装函数自动捕获错误:
import express, { Request, Response, NextFunction } from "express"; import { body, validationResult } from "express-validator"; const router = express.Router(); // 定义async错误处理包装函数 const asyncHandler = (fn: (req: Request, res: Response, next: NextFunction) => Promise<any>) => { return (req: Request, res: Response, next: NextFunction) => { fn(req, res, next).catch(next); }; }; router.post( "/lead", [ body("email").isEmail().withMessage("Email must be valid"), body("name").notEmpty().withMessage("A name has to be provided"), ], asyncHandler(async (req: Request, res: Response) => { const errors = validationResult(req); if (!errors.isEmpty()) { throw new Error("Invalid Email"); } const { email, name } = req.body; console.log("Creating a user..."); res.send({}); }) ); export { router as leadRouter };
方案三:直接返回express-validator验证错误(更贴合场景)
既然已经使用express-validator,可以直接返回验证结果,无需手动抛错:
import express, { Request, Response } from "express"; import { body, validationResult } from "express-validator"; const router = express.Router(); router.post( "/lead", [ body("email").isEmail().withMessage("Email must be valid"), body("name").notEmpty().withMessage("A name has to be provided"), ], async (req: Request, res: Response) => { const errors = validationResult(req); if (!errors.isEmpty()) { return res.status(400).send({ message: "Something went wrong", details: errors.array() }); } const { email, name } = req.body; console.log("Creating a user..."); res.send({}); } ); export { router as leadRouter };
补充说明
Express的错误处理中间件仅能捕获同步代码错误,或通过next(err)主动传递的错误。对于async函数内部的错误,必须手动捕获后传递给next,或通过包装函数自动处理,否则会触发未处理的Promise拒绝,导致服务器崩溃。
内容的提问来源于stack exchange,提问作者Wagner Gauer
相关产品推荐
相关产品推荐

