You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在发送响应前修改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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 14:35:27