Voocii博客
首页博客AI 热榜作品集读书友链工具关于

© 2026 Voocii. Built with Next.js & tRPC.

GitHubXEmailRSS


tRPC:TypeScript 全栈类型安全的 API 框架

后端rick-hayekrick-hayek2026年5月10日

tRPC 中的 RPC 是 Remote Procedure Call,也就是远程过程调用。

如果前端和后端都使用 TypeScript,tRPC 可以让双方共享 API 类型。后端定义过程、输入和返回值,前端调用时就能获得参数提示、返回值推导和编译期错误检查。

一、tRPC 是什么,可以做什么?

tRPC 是一个面向 TypeScript 应用的端到端类型安全 RPC 框架。

后端可以定义类似 userById、post.list、post.create 这样的过程;前端则像调用类型安全函数一样调用它们。实际网络通信仍然通过 HTTP 完成,只是 tRPC 帮我们封装了路径、参数、序列化和类型推导。

它适合:

  • TypeScript 全栈应用;
  • SaaS 和管理后台;
  • 电商、博客和内容系统;
  • 内部工具;
  • React、React Native 或 Electron 客户端;
  • 前后端由同一团队维护的产品。

它不适合把内部 API 直接当作公共 API 使用。若主要消费者是 Python、Java、C# 或 Go 客户端,REST/OpenAPI、GraphQL 或 gRPC 通常更合适。

二、tRPC 的技术原理

1. Router 和 Procedure

Router 用来组织 API,Procedure 是一个可以被远程调用的过程。常见过程类型包括:

  • Query:读取数据;
  • Mutation:创建、修改或删除数据;
  • Subscription:订阅实时数据。

一个 Router 可以嵌套成多个业务领域,例如 user、post、order。最终客户端会得到类似 trpc.post.list 和 trpc.post.create 的类型安全调用入口。

2. 输入校验

tRPC 通常与 Zod 配合。后端为输入定义 Zod Schema,既可以帮助 TypeScript 推导类型,也可以在运行时校验来自网络的真实输入。

这是必要的,因为 TypeScript 类型在编译后会被擦除,不能单独保护网络请求。任何用户提交的数据都应该进行运行时校验。

3. Context

Context 保存一次请求中多个过程都需要的信息,例如:

  • 数据库客户端;
  • 当前用户;
  • Session;
  • 请求对象;
  • 日志对象;
  • 权限信息。

Procedure 可以从 Context 读取这些公共资源,从而避免每个接口重复初始化。

4. Middleware

Middleware 适合实现登录检查、角色权限、日志、计时和限流等通用逻辑。

常见做法是定义 publicProcedure 和 protectedProcedure:公开接口使用前者,需要登录的接口使用后者。这样业务代码不需要反复编写鉴权逻辑。

5. 一次请求的流程

前端调用某个 tRPC 过程后,通常会经历:

  1. 客户端把过程路径和输入参数转换成 HTTP 请求;
  2. 服务端解析过程路径;
  3. tRPC 创建 Context;
  4. Zod 校验输入;
  5. 执行 Middleware;
  6. 执行 Procedure;
  7. 序列化返回值或错误;
  8. 客户端收到结果并更新界面。

因此,tRPC 并没有绕过网络,而是把 HTTP API 封装成了类型安全的远程过程调用。

三、tRPC 的优势和局限

优势

  1. 端到端类型安全:后端输入和输出类型可以自动传递到客户端。
  2. 减少重复代码:不必分别维护大量请求类型、响应类型和客户端封装。
  3. 编辑器体验好:调用时可以获得参数提示、返回值提示和错误检查。
  4. 重构更安全:接口名称和参数变化可以在编译阶段暴露影响范围。
  5. 与 Zod、TanStack Query、React 配合自然。

局限

  1. 非 TypeScript 客户端不能直接享受类型共享。
  2. 对外公开 API 的标准化、文档和跨语言工具链不如 OpenAPI 成熟。
  3. 服务端和客户端耦合更紧,需要更重视版本和边界设计。
  4. tRPC 不能替代数据库设计、权限模型、事务、队列、监控和领域架构。

四、tRPC 如何与前端交互?

后端通常导出整个应用 Router 的类型,例如 AppRouter。客户端使用这个类型创建 tRPC 客户端,再配置 HTTP 链接器。

React 项目中,最常见的组合是 tRPC React 客户端加 TanStack Query。组件可以使用自动推导类型的查询和变更 Hook。

读取数据时,客户端能知道:

  • 输入参数结构;
  • 返回数组还是对象;
  • 每个字段的类型;
  • 加载、成功和错误状态。

提交数据时,Mutation 可以处理:

  • 表单提交;
  • 请求中状态;
  • 成功后的缓存失效;
  • 错误提示;
  • 乐观更新。

TanStack Query 主要负责缓存、重新请求、重试和请求状态;tRPC 主要负责过程路径、输入输出类型和传输层,两者职责不同但配合很好。

在 Next.js Server Components 中,也可以直接使用服务端 caller 或更底层的业务服务。服务器调用自己的服务时,不一定需要再绕一圈发送 HTTP 请求。

五、与 tRPC 配合的上下游框架

上游:前端和 Web 框架

常见组合包括:

  • React;
  • Next.js;
  • TanStack Start;
  • React Native;
  • Expo;
  • 其他能够使用 tRPC 客户端的前端框架。

React + TanStack Query 是目前最容易找到资料和示例的组合。

下游:服务器框架

tRPC 可以接入:

  • Next.js Route Handler;
  • Express;
  • Fastify;
  • Hono;
  • Node.js HTTP Server;
  • Fetch Standard 兼容服务器。

Router 可以与具体 Web 框架分离,所以同一套业务 API 可以根据需要挂载到不同服务器上。

数据库和基础设施

tRPC 不要求特定数据库,常见组合包括:

  • PostgreSQL + Drizzle;
  • PostgreSQL + Prisma;
  • MySQL + Drizzle;
  • SQLite + Drizzle;
  • MongoDB;
  • Supabase;
  • Neon。

其他常见配套工具还有:

  • Zod:运行时校验;
  • Better Auth、Auth.js 或 Clerk:身份认证;
  • React Hook Form:表单;
  • Tailwind CSS:样式;
  • Vitest:单元测试;
  • Playwright:端到端测试。

最推荐的完整组合

对于初学者和现代 TypeScript 全栈项目,我推荐:

Next.js + TypeScript + tRPC + TanStack Query + Zod + PostgreSQL + Drizzle + Better Auth + Tailwind CSS。

它们的职责分别是:

  • Next.js:页面、路由、服务端渲染和部署;
  • React:组件和交互;
  • TypeScript:静态类型;
  • tRPC:类型安全 API;
  • TanStack Query:客户端请求和缓存;
  • Zod:运行时校验;
  • PostgreSQL:关系型数据库;
  • Drizzle:数据库访问和迁移;
  • Better Auth:登录和 Session;
  • Tailwind CSS:样式。

如果团队已经熟悉 Prisma,可以使用 Prisma 替代 Drizzle。选择一个稳定、团队熟悉的 ORM,比追逐工具差异更重要。

六、与 tRPC 同类型的框架有哪些?

REST + OpenAPI

REST 是最通用的 Web API 形式,OpenAPI 可以生成多语言客户端、接口文档、Mock Server 和校验代码。

适合公共 API、跨语言客户端、微服务和需要标准化文档的团队。缺点是需要维护更多显式 Schema 和客户端代码。

GraphQL

GraphQL 让客户端选择需要的字段,适合多个页面数据需求差异很大、需要聚合多个后端服务的场景。

它的能力强,但需要维护 Schema、Resolver、缓存和权限,整体复杂度通常高于 tRPC。

gRPC

gRPC 基于 Protocol Buffers,适合内部微服务、跨语言通信、高性能调用和流式通信。浏览器使用时通常还需要 gRPC-Web 或网关。

Connect RPC

Connect RPC 使用 Protobuf,同时兼顾 RPC 模式、HTTP 和浏览器环境。它适合希望使用 RPC,但又需要跨语言 Schema 和更标准工具链的团队。

如何选择?

可以遵循一个简单原则:

  • TypeScript 单体或全栈应用:优先 tRPC;
  • 跨语言和开放 API:优先 REST/OpenAPI;
  • 数据需求高度灵活:考虑 GraphQL;
  • 内部高性能服务间通信:考虑 gRPC 或 Connect RPC。

七、使用 tRPC 的项目如何暴露 REST API?

tRPC 和 REST 并不冲突。常见做法是:内部 TypeScript 前端使用 tRPC,外部系统使用单独设计的 REST API,两者共享同一套业务服务和数据库访问层。

推荐的分层结构是:

REST Handler / tRPC Procedure ↓ Application Service ↓ Repository / Database

方案一:单独编写 REST Handler

在 Next.js 中,可以创建 app/api/public/posts/route.ts,为外部系统提供 GET、POST、PUT 或 DELETE 接口。

REST Handler 不应该复制一份完整业务逻辑,而应该调用共享的 post service。tRPC Procedure 也调用同一个 service。

这样既能让内部前端获得端到端类型安全,又能为外部系统提供稳定的 HTTP API。

方案二:生成 OpenAPI

部分 tRPC 生态工具可以把 Router 或 Procedure 转换为 OpenAPI,并生成 REST 风格的路径和文档。

这种方案适合想尽量复用 tRPC 定义的团队,但要检查:

  • 过程是否能自然映射到 HTTP 方法和路径;
  • 输入输出 Schema 是否完整;
  • 错误码是否稳定;
  • 认证和限流是否明确;
  • API 版本是否可管理。

并不是每个 RPC 过程都天然适合 REST。复杂动作型接口经常需要人工设计公开路径。

方案三:维护独立的公共 API 层

如果外部 API 很重要,可以把它作为明确的 Public API 层维护:

  • 内部 Web App 使用 tRPC;
  • 外部合作方使用 REST/OpenAPI;
  • 两者共享领域服务;
  • 外部 API 拥有独立的鉴权、限流、审计和版本策略。

不要把内部 Router 的全部过程直接暴露给外部系统。公开 API 应该只暴露稳定、必要且经过权限设计的能力。

八、实践建议

1. 按领域拆分 Router

可以按 user、post、order 等业务领域拆分 Router,避免出现一个几千行的 API 文件。

2. 不要把业务逻辑全部写进 Procedure

Procedure 负责输入校验、Context 获取和调用服务。复杂业务应放到 Application Service 或领域层,这样 REST、定时任务和消息消费者也能复用。

3. 明确公开过程和受保护过程

默认应谨慎开放接口。需要登录的功能使用受保护过程,需要角色控制的功能还要进行权限检查。

4. 设计稳定的错误结构

调用方应该依据稳定的错误码和字段处理失败,而不是依赖可能变化的错误文本。

5. 仍然需要监控和测试

类型安全不能替代生产运维。项目仍然需要日志、错误追踪、慢查询监控、权限审计、限流、单元测试和端到端测试。

结语

tRPC 的核心价值,是让 TypeScript 前后端共享同一份 API 类型,并把接口调用变成编辑器能够理解和检查的代码。

它特别适合前后端由同一团队维护的 TypeScript 全栈应用,但不一定适合作为所有公共 API 的唯一方案。

最重要的架构原则是:tRPC 是传输和类型安全层,不是业务层。把业务逻辑放在可复用的服务层中,内部客户端可以享受 tRPC 的开发体验,外部系统也可以通过稳定的 REST API 接入。

评论 (0)

暂无评论,快来抢沙发吧!

目录
  • 一、tRPC 是什么,可以做什么?
  • 二、tRPC 的技术原理
  • 三、tRPC 的优势和局限
  • 四、tRPC 如何与前端交互?
  • 五、与 tRPC 配合的上下游框架
  • 六、与 tRPC 同类型的框架有哪些?
  • 七、使用 tRPC 的项目如何暴露 REST API?
  • 八、实践建议
  • 结语