Next.js中使用Rewrites代理时HttpOnly Cookie无法生效求助
核心问题:用Next.js Rewrites做服务器端代理时,域名B返回的HttpOnly Cookie会被浏览器识别为B域名的Cookie,但后续通过A域名发起的代理请求属于A域名的同源范围,浏览器不会自动携带该Cookie到代理请求中,导致B服务器无法验证用户身份。
方案一:使用Rewrites内置的proxyOptions配置(推荐)
修改next.config.js中的rewrites规则,添加proxyOptions自动处理Cookie的域名和路径转换,实现双向传递:
async rewrites() { // 提取API域名和当前应用域名 const apiDomain = new URL(process.env.WEB_API_BASEURL).hostname; const appDomain = process.env.NEXT_PUBLIC_APP_DOMAIN; // 示例值:a.example.com return [ { source: '/api/authorization/sign-in', destination: `${process.env.WEB_API_BASEURL}/authorization/sign-in`, proxyOptions: { // 双向重写Cookie域名:响应时将B域名改为A,请求时将A改回B cookieDomainRewrite: { [apiDomain]: appDomain, [appDomain]: apiDomain }, // 重写Cookie路径,匹配代理后的路径规则 cookiePathRewrite: { '/authorization': '/api/authorization' } } }, { source: '/api/authorization/refresh', destination: `${process.env.WEB_API_BASEURL}/authorization/refresh`, proxyOptions: { cookieDomainRewrite: { [apiDomain]: appDomain, [appDomain]: apiDomain } } }, { source: '/api/authorization/userinfo', destination: `${process.env.WEB_API_BASEURL}/authorization/userinfo`, proxyOptions: { cookieDomainRewrite: { [apiDomain]: appDomain, [appDomain]: apiDomain } } } ]; }
关键配置说明
cookieDomainRewrite:自动处理请求和响应阶段的Cookie域名转换,让浏览器将Cookie绑定到A域名,同时代理请求时自动转换回B域名格式。cookiePathRewrite:调整Cookie的路径规则,确保浏览器在访问代理后的/api/authorization/*路径时携带该Cookie。
方案二:通过Next.js Middleware手动处理Cookie传递
如果内置proxyOptions无法满足需求,可通过Middleware拦截请求和响应,手动修改Cookie属性:
- 在项目根目录创建
middleware.js文件:
import { NextResponse } from 'next/server'; export async function middleware(request) { const apiBaseUrl = process.env.WEB_API_BASEURL; const apiDomain = new URL(apiBaseUrl).hostname; // 获取当前应用域名(去除端口号) const appDomain = request.headers.get('host').split(':')[0]; // 构造目标API地址,移除代理前缀/api const targetUrl = new URL( request.nextUrl.pathname.replace('/api', ''), apiBaseUrl ); // 转发请求到B域名服务器,携带原始请求头和Cookie const apiResponse = await fetch(targetUrl, { method: request.method, headers: { ...Object.fromEntries(request.headers), host: apiDomain, // 替换Host头为B域名 }, credentials: 'include', }); // 构造返回给浏览器的响应对象 const response = NextResponse.next(); // 处理B域名返回的Set-Cookie,修改为A域名适配格式 const setCookies = apiResponse.headers.getSetCookie(); setCookies.forEach(cookie => { let modifiedCookie = cookie // 替换Cookie绑定的域名 .replace(new RegExp(`Domain=${apiDomain}`), `Domain=${appDomain}`) // 替换Cookie路径,匹配代理后的路径 .replace('/authorization', '/api/authorization'); // 若当前为HTTPS请求,自动添加Secure属性(确保Cookie仅在HTTPS下传递) if (request.nextUrl.protocol === 'https:' && !modifiedCookie.includes('Secure')) { modifiedCookie += '; Secure'; } response.headers.append('Set-Cookie', modifiedCookie); }); // 复制其他响应头到返回对象中 apiResponse.headers.forEach((value, key) => { if (key !== 'Set-Cookie') { response.headers.append(key, value); } }); return response; } // 仅拦截代理路径下的请求 export const config = { matcher: '/api/authorization/:path*', };
工作原理
- Middleware拦截所有
/api/authorization/*路径的请求,转发到B域名服务器。 - 处理响应时,将B域名的Cookie修改为A域名格式,确保浏览器能正确保存。
- 后续请求触发时,自动将A域名下的Cookie转发给B服务器,完成身份验证流程。
内容的提问来源于stack exchange,提问作者queston
相关产品推荐
相关产品推荐

