Chrome CORS 安全策略解决方案

问题

谷歌在 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 版本后敲启动参数都不管用。

解决思路

目前能想到的解决方案是 接口代理,线下开发不是问题。

具体思路就是在访问服务器时:

  1. 把接口地址改为本域下的地址
  2. 然后在本域接收报文后转发到服务器

这样就跳过了浏览器的跨域策略。

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 配置。

参考

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享