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

Next.js中使用Rewrites代理时HttpOnly Cookie无法生效求助

解决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属性:

  1. 在项目根目录创建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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 22:32:08