Webpack devServer 代理 Cookie 域名重写
cookie 重写
在开发环境中如果接口返回的 cookie 是指定的域名,如 test.com,但是我们本地开发需要使用这个 cookie 信息, 这时候我们需要把接口返回的 cookie 设置为本地开发环境的 localhost,配置如下
先说清楚为什么会出现这个问题。本地起的服务跑在 localhost:8080,接口通过 devServer 代理转发到 https://test.com。后端登录成功后下发 Set-Cookie,里面带着 Domain=.test.com 这个属性。浏览器收到这个响应头时会做一次校验:当前页面的域名是 localhost,和 cookie 声明的 .test.com 不匹配,属于「跨域设置 cookie」,直接静默丢弃。
丢弃是静默的,这是最坑的地方。Network 面板里能看到响应头明明带着 Set-Cookie,但 Application → Cookies 里空空如也,后续请求也不带 cookie,接口全返回 401。很容易误判成后端没下发 cookie。
解决思路就是在代理这一层把 Domain 改掉。响应从目标服务器回来、还没交给浏览器之前,把 Domain=.test.com 改写成 Domain=localhost,浏览器一看域名对得上就会正常存下来。
{
devServer: {
proxy: {
'/api': {
target: 'https://test.com',
onProxyRes: (proxyRes, _req, _res) => {
const cookies = proxyRes.headers['set-cookie'];
if (cookies) {
const cookieRegex = /domain=\.?test.com/i; // 返回的cookie中提取domain
const newCookie = cookies.map(cookie => {
if (cookieRegex.test(cookie)) {
return cookie.replace(cookieRegex, 'domain=localhost');
}
return cookie;
});
delete proxyRes.headers['set-cookie'];
proxyRes.headers['set-cookie'] = newCookie;
}
},
},
}
}
}
onProxyRes 是 http-proxy-middleware 提供的钩子,在代理拿到目标服务器响应、转发给浏览器之前触发,这个时机正好用来改响应头。proxyRes.headers['set-cookie'] 是个数组(一次响应可能下发多个 cookie),所以要 map 逐条处理。
正则里的 \.? 是为了同时兼容 domain=test.com 和 domain=.test.com 两种写法,带点的表示包含子域。/i 标志是因为 cookie 属性名大小写不敏感,后端可能写成 Domain 也可能写成 domain。
更省事的写法
其实 http-proxy-middleware 内置了 cookieDomainRewrite 选项,不用自己写钩子:
proxy: {
'/api': {
target: 'https://test.com',
changeOrigin: true,
cookieDomainRewrite: 'localhost',
},
}
传字符串就是把所有 cookie 的 domain 统一改成这个值,传 ''(空字符串)则是直接删掉 domain 属性——删掉之后浏览器会默认用当前请求的域名,效果一样且更干净。要精细控制的话可以传对象做映射:{ '.test.com': 'localhost', '*': '' }。
配套还有个 cookiePathRewrite,处理 cookie 的 Path 属性和本地路径不一致的情况。
还可能卡住的两个属性
domain 改对了 cookie 还是存不下来,一般是这两个属性在拦:
Secure 属性要求 cookie 只能通过 HTTPS 传输。本地是 http://localhost 的话,带 Secure 的 cookie 会被拒。不过 Chrome 对 localhost 做了特例放宽,实测多数情况下能存;如果不行,就在 onProxyRes 里把 ; Secure 一并去掉,或者给 devServer 开 https: true。
SameSite=None 必须和 Secure 一起用,否则浏览器直接丢弃。后端为了支持跨站场景常配成 SameSite=None; Secure,本地走 http 时这组合就废了。改写时把 SameSite=None 换成 SameSite=Lax 并去掉 Secure 能绕过去。
这些改写只应该出现在开发环境的配置里。生产环境的 cookie 属性由后端按真实域名下发,前端不该也没机会插手。

还没有留言,来发表第一条吧~