前言
跨域资源共享(CORS)大家都不陌生了,面试时候经常会问到,属于是常见的八股文。比如会问到跨域场景、如何设置 CORS。这是我第一次将理论结合实际,不由感叹“纸上得来终觉浅 须知此事要躬行”。
省流:Antd Pro代码提示错误导致走了很多弯路才将项目部署成功。
项目背景
前后端分离开发,前端是 Ant Design Pro。
开发时利用框架能力开启本地代理,使用开发接口(http)测试功能;上线时使用生产接口(https)。同时,后端代码上生产后(提供了 https 接口),前端代码才能上传到 CDN。
-
为什么后端提供
https后前端才能代码打包上线使用?因为前端代码部署的站点使用
https,如果在https站点访问http内容(即开发接口),会被浏览器拦截。报Mixed Content错误(mixed content: the page at XXX was loaded over https, but requested an insecure resource . this request has been blocked; the content must be served over https.)。遇到这个问题的时候还去尝试了其他方案以求在
https站点访问http内容,比如 CSP 的 upgrade-insecure-requests,但是 上线时打包,将产物部署到CDN上。打包产物可以直接以index.html的形式访问,利用静态托管的功能,(OSS浏览器进行上传放到CDN上),并添加配置,如开通子目录,详细见。 -
为什么使用子目录形式?
综合项目目录结构,考虑使用子目录的形式
正文
当接口调不通的时候,八股碎片在我脑中萦绕。跨域是一个需要前后端配合的工作,后端需要设置允许携带凭证、允许的域(携带凭证时需要指定特定域名),需要设置 Set-Cookie 的 Domain 和 Path 等属性,前端需要设置带上凭证(否则浏览器不会把相应内容给到发送者)。跨域还某些情况下可能发送预检请求(OPTIONS)。
这是我们的知识储备,通过一段时间的联调后这些条件看似都满足了。 如后端已经设置
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: xxx
Set-Cookie:authValue=xxxx;Path=/;Domain=xx;
而前端也设置了跨域携带凭证:
credential:'include'
坑爹的事来了,不管怎么联调都没有带上 cookie 。到底是哪出错了呢?我们讨论了这些思路:
-
Same-Site属性:但这个属性是跨站时候用的,和项目场景不匹配。项目场景是一级域名相同,二级域名不同: 在x.A.cn去访问y.A.cn,一级域名都是A.cn。我当初提出这个的时候时看到有消息说chrome把Same-Site的默认属性从None换成Lax,cookie发送策略改变,然后对一些网站造成了问题,所以在尝试了很多方法都失效后,觉得要不把和cookie有关的都试试。最后我通过ModHeader模拟了请求,发现以下配置也没有解决问题:Set-Cookie: ;SameSite=None; Secure -
Domain属性:联调的时候这个属性设置错了。当时设置的是x.A.cn,然后虽然设置成功了,但是去访问y.A.cn的时候就没带出来。这个我后面通过ModHeader测试后解决了。方法是Domain设置一级域名即A.cn。目前的方案能实现登录后鉴权功能但是需要优化
如果
Set-Cookie设置x.A.cn,cookie只设置到了x.A.cn这个二级域名;然后接口请求的是y.A.cn(请求什么网站,就会带上对应网站的cookie),请求的接口没有对应的cookie,拿不到cookie,没认证信息,就会报401。如果
Set-Cookie设置到一级域名.A.cn,那么在x.A.cn去请求y.A.cn就能拿到一级域名的cookie。 但这样的坏处就是刚才说的会把所有设置在.A.cn上的cookie都带上,包括之前设置的与该功能无关的(需要优化的点)。另外,一些图片资源、
css、js资源是不需要带上cookie的,后续需要治理,不然会造成带宽浪费,毕竟性能优化以及成本节约一个需要较早统筹规划、一个要靠长期开源节流,否则越到后期越难优化以及已经浪费了许多成本了。
最终通过模拟 ModHeader 插件修改请求模拟数据,把前端需要的要求都满足了,编辑器代码提示没有报错,后端各种配置也没问题。还是没有解决,心如刀绞啊。突然想起来之前搜索理论的时候发现一篇博文中的前端跨域凭证配置和项目中的有细微差别。
他的配置是这样
可是我也是这样写的但是报错,
所以一开始我非常相信编辑器,然后找了个类似的命名企图“蒙混过关”,我把单词最后的
s
去掉了,结果没有报错。但实际上这个走了 [key: string]: any; 这个类型所以不报错。
但是折腾了很久后效果还是没出来,心如刀绞,面如死灰,此时我已经在电脑前坐了 4 个小时了。到底哪的问题啊?类型提示还能有错误?
抱着将信将疑的态度,我把两个属性在拦截器以及请求的接口那里都加上了,并且忽略掉掉类型报错。结果就是,cookie 带上了,登录进入页面成功。
这一刻,震惊。心里一万头草泥马奔腾。特么的这个类型报错把我给整死了啊。好家伙,之前是全量覆盖,现在让我来抽丝剥茧。通过若干对照实验,我发现就是类型提示报错的那个属性实际上应该是对的,类型定义的时候也是这个属性。但关键是为什么定义对了它还是报错呢?我懒得管了。此时我眼睛干涩,恨不得把电脑砸了。最终录了个视频加上写了这篇文章,好好记录一下值得庆幸的时刻。
参考文档
| 标题 | 链接 |
|---|---|
| 【跨域(CORS)部署血泪史-Antd Pro】 | www.bilibili.com/video/BV1aM… |
| Antd Pro 的 credentials 关键点 | blog.csdn.net/Lcq_best/ar… |
| cookie 好文 | segmentfault.com/a/119000000… |
| 跨域好文 | www.jianshu.com/p/89a377c52… |
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 5 天,点击查看活动详情