在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; }
步骤 2:在 Root Layout 中注入服务端 Cookie
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 是跨域的,需确保:
- API 服务器设置响应头
Access-Control-Allow-Credentials: true Access-Control-Allow-Origin不能设为*,需指定你的 Next.js 域名- 保持
fetch中的credentials: 'include'配置
内容的提问来源于stack exchange,提问作者XCode
相关产品推荐
相关产品推荐

