You need to enable JavaScript to run this app. 如何在Express中统一处理Prisma异常避免Node应用崩溃
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.20 22:15:03