中间件与上下文
为过程添加身份验证和共享上下文。
中间件与上下文 是 CoddyKit 上的免费 TypeScript Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 TypeScript Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 TypeScript Academy 课程共包含 4 节课。
什么是上下文
每个 tRPC 请求都携带一个上下文:所有过程都可以使用的共享数据,例如数据库 client、请求以及当前用户。您可以使用 createContext 函数为每个请求构建一次上下文。
export async function createContext({ req }: { req: Request }) {
const token = req.headers.get('authorization');
const user = await getUserFromToken(token);
return { user };
}为上下文添加类型
tRPC 会从 createContext 推断上下文类型,并将其传递给每个过程。您可以使用该上下文类型初始化实例,这样解析器就能正确识别 ctx 的类型。
import { initTRPC } from '@trpc/server';
type Context = Awaited<ReturnType<typeof createContext>>;
const t = initTRPC.context<Context>().create();读取解析器中的 ctx
在任何过程中,都可以获取类型完整的上下文 ctx。在这里,一个过程会从上下文中读取当前用户。
const me = t.procedure.query(({ ctx }) => {
// ctx.user is typed from createContext
return ctx.user;
});什么是 middleware
middleware 会在过程解析器之前运行。它可以检查权限、执行 log 或修改上下文。它可以调用 next() 继续执行,也可以抛出错误来拒绝请求。
const logger = t.middleware(async ({ path, next }) => {
console.log('calling', path);
return next();
});身份验证 middleware
一种常见的 middleware 用于强制执行身份验证。如果上下文中没有用户,它就会抛出 UNAUTHORIZED 错误;否则就会继续执行解析器。
import { TRPCError } from '@trpc/server';
const isAuthed = t.middleware(({ ctx, next }) => {
if (!ctx.user) {
throw new TRPCError({ code: 'UNAUTHORIZED' });
}
return next();
});使用 next 缩小上下文类型
middleware 可以通过向 next 传入新的 ctx 来细化上下文类型。身份验证检查完成后,可以保证用户存在,因此我们可以将 user 从可能为空的类型缩小为非空类型。
const isAuthed = t.middleware(({ ctx, next }) => {
if (!ctx.user) throw new TRPCError({ code: 'UNAUTHORIZED' });
return next({ ctx: { user: ctx.user } }); // user now non-null
});构建受保护的过程
使用 .use 连接 middleware,即可创建可复用的受保护过程。基于它构建的任何过程都要求进行身份验证,并且能够看到非空的用户。
export const protectedProcedure = t.procedure.use(isAuthed);
const secret = protectedProcedure.query(({ ctx }) => {
return 'Hello ' + ctx.user.name; // user is guaranteed
});公开与受保护
现在您有了两个构建块:publicProcedure 用于开放端点,protectedProcedure 用于需要身份验证的端点。选择正确的基础过程,可以在类型层面和运行时层面记录并强制执行访问控制。
const ping = publicProcedure.query(() => 'pong');
const account = protectedProcedure.query(({ ctx }) => ctx.user);带类型的 ctx 传递
缩小后的上下文会继续传递:由于 protectedProcedure 保证了 ctx.user 存在,所有基于它构建的解析器都能直接看到非空类型,无需再次检查。middleware 只需编码一次这一不变量。
// In any protectedProcedure resolver:
// ctx.user is User, not User | null组合 middleware
middleware 可以通过链式调用 .use 进行组合。您可以先应用日志记录,再进行身份验证,最后检查角色。每个 middleware 都会按顺序运行,并且都可以进一步缩小传递给下一个 middleware 的上下文类型。
const adminProcedure = protectedProcedure.use(({ ctx, next }) => {
if (ctx.user.role !== 'admin') {
throw new TRPCError({ code: 'FORBIDDEN' });
}
return next();
});完整图景
上下文提供每个请求的数据,middleware 对其进行保护和细化,而专用过程则将这些保证固化下来。再结合输入模式和类型化 client,您就能获得一个在运行时和编译时都安全的端到端接口。
// createContext -> ctx
// middleware -> auth + narrowing
// protectedProcedure -> guaranteed ctx.user
// typed client -> end-to-end safety快速检查
测试您对上下文和 middleware 的理解。
回顾
您已经使用上下文和 middleware 保护了一个 tRPC 接口。
createContext构建每个请求的共享数据,其类型通过initTRPC.context指定。- middleware 会在解析器之前运行,以保护并细化上下文。
- 将
ctx传递给next会缩小其类型。 protectedProcedure将身份验证固化下来,使解析器获得非空用户。
您已经完成了端到端类型安全课程。
用 AI 导师学习 TypeScript — 免费
在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。
- 课程
- 101
- 课程
- 352
常见问题解答
「中间件与上下文」课时是免费的吗?
是的 — 「中间件与上下文」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 TypeScript Academy 课程的其余内容,请升级到 CoddyKit PRO。 TypeScript Academy 课程共包含 4 节课。
「中间件与上下文」这节课中我会学到什么?
为过程添加身份验证和共享上下文。 你通过在浏览器中直接运行的动手代码来练习 TypeScript Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 TypeScript Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 TypeScript Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。
「中间件与上下文」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 TypeScript Academy 课中编写并运行代码吗?
能。每节 TypeScript Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- tRPC 架构
- 定义路由器与过程
- 客户端—服务器类型推断
- 中间件与上下文