如何在发送响应前修改tRPC错误?
tRPC 服务端错误处理实操方案
全局错误拦截(中间件实现)
通过tRPC中间件可以全局捕获所有路由的错误,统一处理或修改错误信息、添加日志等:
import { initTRPC, TRPCError } from '@trpc/server'; import type { Context } from './your-context-file'; const t = initTRPC.context<Context>().create(); // 全局错误处理中间件 const errorMiddleware = t.middleware(async ({ next, ctx }) => { try { return await next(); } catch (err) { // 处理错误:添加自定义信息、日志,或转换错误类型 if (err instanceof Error) { // 示例:给数据库错误添加友好提示 if (err.name === 'PrismaClientKnownRequestError') { console.error('DB Error:', err); throw new TRPCError({ code: 'BAD_REQUEST', message: '数据操作失败,请检查输入内容', cause: err, }); } // 给普通错误追加自定义属性 (err as any).serverTimestamp = Date.now(); } // 抛出修改后的错误(或新错误) throw err; } }); // 将中间件应用到所有公开/私有路由 export const publicProcedure = t.procedure.use(errorMiddleware); export const router = t.router;
单个路由/过程的错误处理
针对特定业务路由,可以单独在逻辑内捕获并处理错误:
import { z } from 'zod'; import { publicProcedure, router } from './trpc'; export const appRouter = router({ getPost: publicProcedure .input(z.object({ postId: z.string() })) .query(async ({ input, ctx }) => { try { const post = await ctx.db.post.findUnique({ where: { id: input.postId }, }); if (!post) { // 主动抛出tRPC标准错误 throw new TRPCError({ code: 'NOT_FOUND', message: '请求的帖子不存在', }); } return post; } catch (err) { // 针对该路由的个性化错误处理 if (err instanceof TRPCError && err.code === 'NOT_FOUND') { err.message = '未找到指定帖子,请确认ID是否正确'; } throw err; } }), });
自定义错误类型与统一格式化
如果需要自定义错误结构,可以创建自定义错误类,结合全局中间件统一转换为tRPC标准错误:
// 自定义错误类 class AppError extends Error { public code: string; public details?: Record<string, any>; constructor(code: string, message: string, details?: Record<string, any>) { super(message); this.code = code; this.details = details; this.name = 'AppError'; } } // 在全局中间件中捕获并转换 const errorMiddleware = t.middleware(async ({ next }) => { try { return await next(); } catch (err) { if (err instanceof AppError) { // 映射到tRPC官方错误码 const trpcCode = err.code === 'INVALID_INPUT' ? 'BAD_REQUEST' : 'INTERNAL_SERVER_ERROR'; throw new TRPCError({ code: trpcCode as any, message: err.message, cause: err.details, }); } // 兜底处理所有未知错误 throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR', message: '服务端发生未知错误', }); } });
关键注意事项
- 务必使用
TRPCError抛出业务错误,这样tRPC会自动处理错误的序列化,前端可通过error.data.code获取标准错误码 - 全局中间件适合处理通用逻辑(如日志、错误格式化),路由级处理用于个性化业务场景
- 不要忽略错误的
cause属性,它可以保留原始错误信息,便于排查问题
内容的提问来源于stack exchange,提问作者HMR
相关产品推荐
相关产品推荐

