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

如何修改最新create-t3-app创建受保护tRPC Procedure并解决类型错误?

解决T3 App中Clerk身份验证与tRPC上下文兼容问题

问题核心

修改createTRPCContext参数类型为trpcNext.CreateNextContextOptions后,RSC环境下的server.ts调用时因传入{headers: Heads}类型不匹配报错;同时初始用opts.headers调用getAuth时存在类型不兼容问题。

解决方案:让上下文函数兼容两种调用场景

我们需要让createTRPCContext同时支持API路由(带req/res)和RSC(仅带headers)两种调用场景,具体修改如下:

1. 更新createTRPCContext定义

在./src/server/api/trpc.ts中,将参数类型改为联合类型,并内部适配两种场景的身份验证获取:

import type * as trpcNext from "@trpc/server/adapters/next";
import { getAuth } from "@clerk/nextjs/server";
import { TRPCError } from "@trpc/server";

// 定义兼容RSC和API路由的上下文参数类型
type CreateContextOptions = 
  | { headers: Headers }
  | trpcNext.CreateNextContextOptions;

export const createTRPCContext = async (opts: CreateContextOptions) => {
  // 根据参数类型选择正确的getAuth调用方式
  const auth = "req" in opts ? getAuth(opts.req) : getAuth(opts.headers);
  const { userId } = auth;

  return {
    db,
    userId,
    // 统一传递headers,方便后续使用
    headers: "headers" in opts ? opts.headers : opts.req.headers,
  };
};

// 定义privateProcedure
export const privateProcedure = t.procedure.use(async ({ ctx, next }) => {
  if (!ctx.userId) {
    throw new TRPCError({
      code: "UNAUTHORIZED",
      message: "必须登录才能执行此操作",
    });
  }
  // 向下传递确保userId非空的上下文
  return next({
    ctx: {
      ...ctx,
      userId: ctx.userId,
    },
  });
});

2. 保留server.ts中的原有调用

此时./src/trpc/server.ts里的createContext函数无需修改,因为{headers: heads}完全符合我们定义的联合类型:

// ./src/trpc/server.ts
import "server-only";

import { headers } from "next/headers";
import { cache } from "react";

import { createCaller } from "@/server/api/root";
import { createTRPCContext } from "@/server/api/trpc";

const createContext = cache(() => {
  const heads = new Headers(headers());
  heads.set("x-trpc-source", "rsc");
  return createTRPCContext({
    headers: heads,
  });
});

export const api = createCaller(createContext);

3. 验证API路由兼容性

tRPC的Next.js适配器在API路由中调用createTRPCContext时,会传入trpcNext.CreateNextContextOptions类型的参数,我们的联合类型也能完美适配,无需额外修改。

关键说明

  • 联合类型CreateContextOptions覆盖了RSC和API路由两种调用场景,解决了类型不匹配问题
  • 通过"req" in opts类型守卫,在函数内部区分两种场景,正确调用getAuth
  • privateProcedure中通过校验userId是否存在,实现了身份验证拦截

内容的提问来源于stack exchange,提问作者Austin Thaldorf-Huelsbeck

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 05:52:45