如何在Express中统一处理Prisma异常避免Node应用崩溃
根本原因
Express 4.x 及更早版本不会自动捕获异步路由/中间件抛出的错误。Prisma 所有数据库操作都是异步 Promise,如果你没有显式捕获异步错误并传递给 next() 函数,错误就会触发 Node.js 的 unhandledRejection 事件,直接导致进程崩溃,不会进入你定义的全局错误处理器。
实现步骤
步骤1:处理异步路由错误传递
你可以通过一个异步包装工具函数,自动捕获所有异步路由的错误并传递给全局错误处理器:
// utils/asyncWrapper.ts import { Request, Response, NextFunction, RequestHandler } from "express"; export const asyncWrapper = (fn: RequestHandler) => (req: Request, res: Response, next: NextFunction) => { Promise.resolve(fn(req, res, next)).catch(next); };
所有用到 Prisma 操作的异步路由都用该函数包裹:
// 路由示例 import { asyncWrapper } from "./utils/asyncWrapper"; // 示例:查询用户列表的路由 server.get('/users', asyncWrapper(async (req, res) => { const users = await prisma.user.findMany(); res.json(users); }));
如果使用 Express 5.x 版本可以省略该步骤,Express 5 已原生支持异步错误自动捕获,不需要额外包装。
步骤2:优化全局错误处理器适配 Prisma 错误
你可以扩展原有错误处理器,根据 Prisma 官方定义的错误类型做分类处理,充分利用 Prisma 提供的错误信息返回更合理的响应:
// errorHandler.ts import { Prisma } from "@prisma/client"; import { NextFunction, Response, Request } from "express"; const errorHandler = (err: any, req: Request, res: Response, next: NextFunction) => { console.error(err.stack); // 处理Prisma已知请求错误,如唯一约束冲突、外键不存在等场景 if (err instanceof Prisma.PrismaClientKnownRequestError) { switch(err.code) { case 'P2002': // 唯一约束冲突错误 return res.status(409).send('资源已存在,提交的数值违反唯一约束规则'); case 'P2025': // 操作的记录不存在 return res.status(404).send('目标资源不存在,无法完成操作'); // 可根据业务需求自行扩展更多Prisma错误码的处理逻辑 default: return res.status(400).send(`数据操作错误:${err.message}`); } } // 处理Prisma参数校验错误 if (err instanceof Prisma.PrismaClientValidationError) { return res.status(400).send('请求参数不符合格式要求,请检查后重试'); } // 处理Prisma数据库连接错误 if (err instanceof Prisma.PrismaClientInitializationError) { return res.status(503).send('数据库连接异常,请稍后重试'); } // 通用错误返回 res.status(err.statusCode || 500).send(err.message || "Internal Server Error"); }; export default errorHandler;
步骤3:添加进程级兜底错误捕获(可选)
为了避免漏网的未处理错误直接导致服务崩溃,可以在入口文件添加全局事件监听兜底:
// index.ts 入口文件添加 process.on('unhandledRejection', (err: Error) => { console.error('未捕获的异步错误:', err); // 可在此处添加错误日志上报逻辑 }); process.on('uncaughtException', (err: Error) => { console.error('未捕获的同步错误:', err); // 可在此处添加错误日志上报逻辑,根据错误严重程度判断是否需要重启进程 });
内容的提问来源于stack exchange,提问作者conaticus
相关产品推荐
相关产品推荐

