Skip to content

参考:procedure 模式、对比与易错点速查

基于 tRPC v11 · 核于 2026-08

速查

  • tRPC 定义:TS 全栈端到端类型安全 RPC 框架,零 codegen,前后端共享类型。
  • 核心单元:procedure(query/mutation/subscription),input 用 Zod 校验 + 推导类型。
  • 组织:router 嵌套成树,路径即类型(trpc.user.list)。
  • 依赖注入:context(每请求构造),注入用户/DB;中间件封装 publicProcedure/protectedProcedure。
  • 集成:React 适配器底层是 TanStack Query(缓存/失效/乐观更新);v11 支持 RSC 的 caller 模式。
  • 限制:强绑定 TS 全栈,非 TS 后端/客户端不适用;无 introspection。

一、procedure 类型与 API 速查

API用途示例
t.procedure创建过程(公开)t.procedure.query(...)
.use(mw)挂中间件(鉴权/日志).use(isAuthed)
.input(zodSchema)参数校验 + 类型推导.input(z.object({ id: z.string() }))
.output(zodSchema)返回值校验(可选).output(userSchema)
.meta({...})挂元数据(角色等).meta({ requiredRole: 'admin' })
.query(handler)读(GET 语义).query(({ ctx, input }) => ...)
.mutation(handler)写(POST 语义).mutation(({ ctx, input }) => ...)
.subscription(handler)实时(observable).subscription(({ ctx }) => observable(...))

二、router 组织模式

模式写法前端访问
嵌套 router(推荐)t.router({ user: userRouter, post: postRouter })trpc.user.list / trpc.post.publish
mergeRoutersmergeRouters(a, b)扁平,无命名空间(少用)
proceduret.router({ list: t.procedure.query(...) })trpc.list
  • 大型项目惯例:每领域一个 router 文件(userRouter/postRouter),根 router 聚合,前端按命名空间访问。

三、鉴权与 procedure 工厂模式

ts
const isAuthed = t.middleware(({ ctx, next }) => {
  if (!ctx.user) throw new TRPCError({ code: "UNAUTHORIZED" });
  return next({ ctx: { user: ctx.user } });
});
export const publicProcedure = t.procedure;
export const protectedProcedure = t.procedure.use(isAuthed);
工厂用途
publicProcedure无需登录(如 health、登录接口本身)
protectedProcedure需登录
adminProcedure需 admin 角色(protectedProcedure.use(isAdmin)

四、TRPCError code 映射

codeHTTP含义
PARSE_ERROR400请求体解析失败
BAD_REQUEST400参数校验失败(Zod 拒绝)
UNAUTHORIZED401未登录
FORBIDDEN403无权限
NOT_FOUND404资源不存在
TIMEOUT408超时
CONFLICT409冲突(如重复创建)
INTERNAL_SERVER_ERROR500服务端异常(含未捕获错误)
  • 惯例:抛 TRPCError({ code, message }),不要抛原生 Error(丢失 code,被当 500)。

五、与 REST / GraphQL / NestJS 对照

维度RESTGraphQLtRPCNestJS
模型resource(名词)schema + resolverprocedure(动词)DI + 装饰器
类型安全OpenAPI+codegenschema+codegen零 codegen 端到端HTTP 边界断
语言无关❌(TS 专属)
introspectionOpenAPI 文档✅ 运行时自省Swagger 文档
协议标准 HTTP自定义 HTTP自定义 HTTP+JSON标准 HTTP
定位协议查询语言+协议TS 通信契约应用框架
  • 本质:REST/GraphQL 是协议(语言无关),tRPC 是 TS 专属强类型方案,NestJS 是应用框架(可与 tRPC 共存)。

六、易错点清单

  • "tRPC 是语言无关的协议":错。tRPC 强绑定 TypeScript 全栈,前后端都必须是 TS,非 TS 后端/客户端不适用——这是它与 REST/GraphQL 的根本分野。
  • "tRPC 需要 codegen":错。tRPC 的核心卖点就是零 codegen——前端导入后端 router 的类型(仅类型,不含运行时),靠 TS 条件类型推断。GraphQL 才需要 codegen。
  • "前端把整个 router 运行时打包进去了":错。import type { AppRouter } 只导入类型,编译期被擦除,运行时前端不含 router 代码。
  • "input 不校验也没事":错。.input(zodSchema) 同时管运行时校验与类型推导。不写 input,handler 拿不到类型化参数,前端调用也无类型保护。
  • "mutation 也能缓存":错。query 映射 TanStack Query 的 useQuery(可缓存),mutation 是 useMutation(默认不缓存,触发后通常 invalidate query)。
  • "抛原生 Error 前端能拿到 code":错。throw new Error() 丢失 code,被 tRPC 当 INTERNAL_SERVER_ERROR(500)。要语义化错误必须 throw new TRPCError({ code, message })
  • "tRPC 有 introspection,能运行时发现 API":错。tRPC 无 introspection(这是与 GraphQL 的区别),前端必须编译期知道 router 路径。
  • "tRPC 比 GraphQL 更类型安全":片面。TS 全栈下 tRPC 类型同样强(甚至更紧),但 GraphQL 在多语言/introspection/按需字段上有优势,不能一概而论。
  • "tRPC 和 NestJS 二选一":错。二者不同层:NestJS 管后端架构(DI/模块),tRPC 管前后端类型契约。大型 TS 项目可 NestJS + tRPC 共存。
  • "v10 升 v11 只改了版本号":错。v11 重构了 createTRPCClient/链接 API,对齐 TanStack Query v5,RSC 集成稳定化——有迁移成本。
  • "subscription 必须用 WebSocket":v11 起不一定。SSE/WebRTC 适配器可选,纯推送场景可不上 WebSocket。

七、进阶方向(链接其他叶)

  • NestJS —— 企业级 DI 框架,可与 tRPC 共存(Nest 架构 + tRPC 端点)
  • Express —— tRPC 可挂在 Express/Next API route 上
  • Fastify —— tRPC 的 httpBatchLink 适配器之一
  • [微服务架构] —— tRPC 主要面向前后端通信,服务间通信另见微服务章

权威链接