问题
谷歌在 80 版本的时候使用了 HTTP 响应头属性 SameSite,它用于声明 Cookie 是否仅限于第一方或者同一站点上下文中。
简单地说,SameSite
决定了跨域时 Cookie 是否能够存储。
按理说这是后端的事,让后端加响应头就行了,但是 这个属性在非 https
协议时是强制开启的。 这就很麻烦了,线下搞个 https
成本太高。
Chrome 在 80 ~ 91 版本时,可以修改浏览器配置关闭此功能。91 版本后浏览器配置隐藏了此功能,可以通过增加启动参数 --disable-features=SameSiteByDefaultCookies
来修改这个隐藏功能,但是 Chromium Projects 项目组在最新的 更新文档 提到:
Mar 18, 2021: The flags #same-site-by-default-cookies and #cookies-without-same-site-must-be-secure have been removed from chrome://flags as of Chrome 91, as the behavior is now enabled by default. In Chrome 94, the command-line flag –disable-features=SameSiteByDefaultCookies,CookiesWithoutSameSiteMustBeSecure will be removed.
大致就是说这个隐藏功能也要删了,94 版本后敲启动参数都不管用。
解决思路
目前能想到的解决方案是 接口代理,线下开发不是问题。
具体思路就是在访问服务器时:
- 把接口地址改为本域下的地址
- 然后在本域接收报文后转发到服务器
这样就跳过了浏览器的跨域策略。
Webpack 的 devServer.proxy
可以用来监听本地某一资源的请求并转发。
比如当前 Webpack 运行在 localhost:8080
上,想对 server.com
发送数据,那么 Webpack 可以这样配置:
module.exports = {
//...
proxy: {
"/api": "http://localhost:3000",
},
};
复制代码
此时请求 /api/users
现在会被代理到请求 http://localhost:3000/api/users
,并且不会有跨域影响。
这个功能支持路径重写,比如:
module.exports = {
//...
proxy: {
"/api": {
target: "http://localhost:3000/xxx/v1",
pathRewrite: { "^/api": "" },
},
},
};
复制代码
这个 pathRewrite
逻辑就是 String.prototype.replace
,把正则 ^/api
匹配的位置替换为空字符串,然后拼接到 target
后面。
此时请求 /api/users
现在会被代理到请求 http://localhost:3000/xxx/v1/users
,并且不会有跨域影响。
更多复杂的配置可以查看 http-proxy-middleware。
在 Vue-cli 中使用代理
题设:
- 本地开发服务器地址为:
localhost:8080
; - 服务器接口地址为:
server.com/api-server
,其中/api-server
是接口前缀;
在 Vue-cli 中实现本地接口代理:
在项目中创建或修改 项目根路径/Vue.config.js
文件的 Webpack 配置如下:
module.exports = {
// other option...
chainWebpack: (config) => {
config.devServer.proxy({
"/api": {
target: "http://server.com/api-server",
pathRewrite: { "^/api": "" },
},
});
},
};
复制代码
此时在程序中你想访问 http://server.com/api-server/login
的时候,使用以下 /api/login
即可,比如:
fetch("/api/login", {
method: "POST",
//...
});
复制代码
其他和注意
注意:Webpack 本地代理不会热更新,每次改完要重启项目。
其他:
- 线上出现跨域怎么办?让后端设置反向代理即可,或者让后端在响应头里面加上 SameSite 属性。
- Vue-cli 还可以使用 configureWebpack 来进行配置。
- 其他脚手架请参考对应的自定义 Webpack 配置。