Next.js集成tRPC实现SSR时context无法获取cookies问题
问题根因
tRPC上下文中无法获取携带JWT的Cookie,核心是三个配置漏项:
- 未正确在tRPC API路由中绑定上下文传参,请求对象
req没有传入createContext方法 - 未配置SSR场景下的请求透传,服务端预取数据时没有把页面请求的Cookie带到tRPC上下文
- 跨域场景下客户端请求未开启携带凭证配置,请求头不会自动带Cookie
分步修复
1. 修正tRPC API路由配置
首先检查pages/api/trpc/[trpc].ts文件,确保createContext直接传入handler配置,不要额外包一层丢失参数:
import * as trpcNext from '@trpc/server/adapters/next'; import { appRouter } from '@/server/routers/_app'; import { createContext } from '@/server/context'; export default trpcNext.createNextApiHandler({ router: appRouter, createContext, // 直接传入,框架会自动注入req/res参数 onError({ error }) { if (error.code === 'INTERNAL_SERVER_ERROR') { console.error('tRPC服务错误', error); } }, });
2. 优化上下文逻辑,增加容错
修改tRPC上下文文件,去掉参数可选标记,增加JWT校验容错,避免无Cookie时接口直接报错:
import * as trpc from '@trpc/server'; import * as trpcNext from '@trpc/server/adapters/next'; import jwt from 'jsonwebtoken'; import { prisma } from '@/lib/prisma'; export const createContext = async (opts: trpcNext.CreateNextContextOptions) => { const { req, res } = opts; let user = null; // 此时req.cookies可正常读取 console.log('当前请求携带的Cookie列表:', req.cookies); const token = req.cookies.token; if (token) { try { user = jwt.verify(token, process.env.JWT_SECRET as string) as User; } catch (err) { user = null; } } return { req, res, prisma, user }; }; type Context = trpc.inferAsyncReturnType<typeof createContext>; export const createRouter = () => trpc.router<Context>();
3. 配置SSR数据预取,透传请求上下文
不要直接在客户端组件靠useQuery拉取SSR阶段需要的数据,需要在getServerSideProps中预取数据,把页面请求的req/res直接传入tRPC上下文:
修改[username].tsx页面代码:
import { NextPage } from 'next'; import { GetServerSideProps } from 'next'; import { Text } from '@chakra-ui/react'; import { createServerSideHelpers } from '@trpc/react-query/server'; import SuperJSON from 'superjson'; import { appRouter } from '@/server/routers/_app'; import { createContext } from '@/server/context'; import { trpc } from '@/utils/trpc'; const UserPage: NextPage<{ username: string }> = ({ username }) => { // 会优先读取服务端预取的脱水数据,不会重复在客户端发请求 const userQuery = trpc.useQuery(["user.by-username", { username }]); return <Text>{userQuery.data?.id}</Text>; }; export const getServerSideProps: GetServerSideProps = async (ctx) => { const username = ctx.params?.username as string; if (!username) { return { notFound: true }; } // 把当前页面请求的req/res传入tRPC上下文,Cookie会自动携带 const helpers = createServerSideHelpers({ router: appRouter, ctx: await createContext({ req: ctx.req, res: ctx.res, }), transformer: SuperJSON, }); // 服务端预取用户数据 await helpers.fetchQuery(["user.by-username", { username }]); return { props: { trpcState: helpers.dehydrate(), username, }, }; }; export default UserPage;
4. 补全客户端请求配置(跨域场景必填)
如果你的前端服务和API服务不同域,需要在tRPC客户端初始化配置中开启携带凭证,确保客户端发请求时自动带Cookie:
// utils/trpc.ts import { createTRPCReact } from '@trpc/react-query'; import { httpBatchLink } from '@trpc/client'; import superjson from 'superjson'; import type { AppRouter } from '@/server/routers/_app'; export const trpc = createTRPCReact<AppRouter>(); export const trpcClient = trpc.createClient({ transformer: superjson, links: [ httpBatchLink({ url: process.env.NEXT_PUBLIC_TRPC_URL || '/api/trpc', fetch(url, options) { return fetch(url, { ...options, credentials: 'include', // 允许跨域请求携带Cookie }); }, }), ], });
验证方式
改完配置后重启Next.js服务,访问用户页面时,服务端控制台会正常打印Cookie内容,SSR阶段就能直接拿到JWT解析出的用户信息,不会出现上下文拿不到Cookie的问题。
内容的提问来源于stack exchange,提问作者vasek
相关产品推荐
相关产品推荐

