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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 01:18:24