Next.js中间件修改自定义Fetch请求头无效?SSR添加Cookie求助
我想在Next.js的服务端渲染(SSR)过程中给请求头自动添加Cookie,现在已经封装了自定义API模块简化Fetch调用:
// custom-api.ts export const headers = new Headers({ credentials: 'include', }); const api = { get: async(path: string, options?: any) => { const res = await fetch(`${path}`, { headers, ...options, }); return await res.json(); }, };
但在SSR时,每次都得在getServerSideProps里手动设置请求头,操作太繁琐:
// import { getData } from '@/services/main'; export const getServerSideProps = async (context) => { const { cookies } = context.req; const queryClient = new QueryClient(); queryClient.prefetchQuery(['query-key'], getData); return { props: {} }; };
于是尝试用中间件处理,但修改后的请求头没生效,想知道原因:
//src/middleware.ts import { headers } from '@/utils/api'; export async function middleware(request: NextRequest) { const { cookies } = request; headers.set('Cookie', `my-cookie=${cookies.get('my-cookie')?.value}`); // 值能正常获取到 NextResponse.next(); }
不生效的核心原因
- 全局Headers实例共享冲突:你导出的
headers是全局单例对象,中间件在每个请求前执行时修改它,会导致多个请求间的Cookie互相污染。而且Next.js服务端环境中,这种全局修改不会自动关联到getServerSideProps里独立发起的Fetch请求上下文。 - 中间件作用范围不匹配:中间件负责处理客户端到Next.js服务器的入站请求,它修改的是进入Next.js的请求头,但不会直接影响你在
getServerSideProps里手动创建的Fetch请求头——这些请求是Next.js服务器向外部API发起的,和中间件处理的入站请求是两个独立的请求链路。 - 中间件代码遗漏返回值:你的中间件最后没返回
NextResponse.next(),这会导致中间件逻辑根本不执行,但就算补上,也解决不了前面两个核心问题。
可行的解决方案
方案1:通过上下文传递Cookie(Pages Router推荐)
改造自定义API,让它支持接收自定义Headers,不再依赖全局单例:
// custom-api.ts const createApi = (customHeaders?: Headers) => { const baseHeaders = new Headers({ credentials: 'include', ...customHeaders, }); return { get: async(path: string, options?: any) => { const res = await fetch(`${path}`, { headers: baseHeaders, ...options, }); return await res.json(); }, }; }; export default createApi;
然后在getServerSideProps里创建带当前请求Cookie的API实例:
// 页面组件文件 import createApi from '@/utils/custom-api'; import { getData } from '@/services/main'; export const getServerSideProps = async (context) => { const { cookies } = context.req; // 把当前请求的所有Cookie拼接成请求头格式 const cookieHeader = Object.entries(cookies) .map(([key, value]) => `${key}=${value}`) .join('; '); const api = createApi(new Headers({ Cookie: cookieHeader })); // 把api实例传给getData,让内部用这个实例发起请求 const queryClient = new QueryClient(); await queryClient.prefetchQuery(['query-key'], () => getData(api)); return { props: {} }; };
方案2:利用请求上下文自动获取(App Router推荐)
如果用的是App Router,可以在Server Component里直接用Next.js提供的headers()函数获取当前请求头,自动传递给API:
// custom-api.ts import { headers } from 'next/headers'; export const api = { get: async(path: string, options?: any) => { // 从当前请求上下文获取完整请求头,再添加自定义配置 const requestHeaders = new Headers(headers()); requestHeaders.set('credentials', 'include'); const res = await fetch(`${path}`, { headers: requestHeaders, ...options, }); return await res.json(); }, };
这种方式下,Server Component里的API调用会自动带上当前请求的Cookie,不需要手动处理。
内容的提问来源于stack exchange,提问作者minami
相关产品推荐
相关产品推荐

