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

在Next.js(App Router)中通过Relay将请求Cookie传递至fetch()调用

核心思路

分服务端渲染(SSR)和客户端渲染(CSR)两种场景处理:

  • SSR 阶段:在服务器端组件中直接获取 Cookie,注入到 Relay Environment 的请求头中
  • CSR 阶段:通过配置 fetch 的 credentials 参数,自动携带浏览器 Cookie

步骤 1:封装 Relay Environment 创建函数

创建支持传入自定义请求头的工厂函数,区分服务端/客户端环境复用逻辑:

// lib/relay/createEnvironment.ts
import { Environment, Network, RecordSource, Store } from 'relay-runtime';

// 客户端侧缓存环境实例,避免重复创建
let clientEnv: Environment | null = null;

export function createRelayEnvironment(initialHeaders?: HeadersInit) {
  // 客户端复用已创建的环境
  if (typeof window !== 'undefined' && clientEnv) {
    return clientEnv;
  }

  const network = Network.create(async (operation, variables) => {
    const fetchOpts: RequestInit = {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      credentials: 'include', // 客户端请求自动携带Cookie
      body: JSON.stringify({
        query: operation.text,
        variables,
      }),
    };

    // 服务端传入的Cookie合并到请求头
    if (initialHeaders) {
      fetchOpts.headers = { ...fetchOpts.headers, ...initialHeaders };
    }

    const res = await fetch('/api/graphql', fetchOpts);
    return res.json();
  });

  const store = new Store(new RecordSource());
  const newEnv = new Environment({ network, store });

  // 客户端缓存实例
  if (typeof window !== 'undefined') {
    clientEnv = newEnv;
  }

  return newEnv;
}

Root Layout 作为服务器端组件,可直接调用 cookies() 获取请求中的 Cookie,传给 Relay Environment:

// app/layout.tsx
import { cookies } from 'next/headers';
import { RelayEnvironmentProvider } from 'react-relay';
import { createRelayEnvironment } from '@/lib/relay/createEnvironment';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  // 把所有Cookie转为请求头格式的字符串
  const cookieHeader = cookies().toString();
  const environment = createRelayEnvironment({ Cookie: cookieHeader });

  return (
    <html lang="zh-CN">
      <body>
        <RelayEnvironmentProvider environment={environment}>
          {children}
        </RelayEnvironmentProvider>
      </body>
    </html>
  );
}

为什么之前的中间件方案无效?

Next.js 的 process.env 是构建时注入的全局变量,运行时通过中间件修改的 process.env 无法隔离到单个请求的上下文中,自然无法传递到后续的 fetch 调用里——每个请求的上下文是独立的,全局变量不适合存储请求级别的动态数据。

跨域 API 额外配置

如果 API 是跨域的,需确保:

  1. API 服务器设置响应头 Access-Control-Allow-Credentials: true
  2. Access-Control-Allow-Origin 不能设为 *,需指定你的 Next.js 域名
  3. 保持 fetch 中的 credentials: 'include' 配置

内容的提问来源于stack exchange,提问作者XCode

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 12:35:23