新手对跨域的误解以及Credentials对跨域配置的坑

2021-08-19 14:59:22 浏览数 (1)

在学习过程中,跨域似乎很简单,无非就是“当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域”;

无非就是“后端加一下跨域的相关响应头即可”。

但是在前后联调过程中,发现跨域并没有那么容易解决。

后端环境是springboot,一开始用的重写WebMvcConfigurer里面的addCorsMappings,添加相应的响应头,但是发现无效。

百度一下猜测可能是因为过滤器链的顺序问题,因此单独写了一个Filter并将order设为较靠前的位置。

然而,设置的ACCESS_CONTROL_ALLOW_ORIGIN明明是“*”,但是前端得到的却是火狐的一个扩展(具体值我不记得了)。

(后面大概猜测到,由于我用的是火狐插件Rester进行的接口测试,因此origin自带为火狐扩展的专用默认值)

前端要求必须看到“*”号,于是上nginx反向代理,配置参考

但是,前端有多名人员,其中有人成功进行了跨域访问,还有个哥们一直跨域失败。

难道跨域配置在前端还做了什么拦截吗?

经过排查,那位跨域失败的兄弟发现将axios的所有config删除后就能正常访问了。

但是,按理来说,不可能为了跨域就不让用axios的config了,所以应该是其中的某个配置造成的问题,不过具体的原因那个前端没有跟我说,我也不大清楚。

本以为解决了,结果前端很快跟我说,get可以访问,post依旧存在跨域。

一环扣一环,于时又是一波折腾,中间的曲折过程就不说了。

最终发现:

Credentials设为 true之后,Access-Control-Allow-Origin就不能设置为 * 了!

因此需要将Credentials设为false,然后前端就能得到Access-Control-Allow-Origin=*;

而此时,nginx设置的headers信息就需要注释掉,不然存在多重重复头信息,也会报错。

Credentials是用与cookie校验的,如果要设为true,则进行如下配置 responce.set(‘Access-Control-Allow-Origin’, request.get(‘origin’)); 但是这样,'Access-Control-Allow-Origin’拿到的就不是*,而是每个访问端的专属Origin。

此外,我个人对跨域一直存在误解,比如那个兄弟跟我说/api/sms有跨域限制,于是我用postman浏览器测试了该接口(项目已经部署在服务器中,我这里的测试也属于远程调用),发现没有跨域问题,而且正常返回了ACCESS_CONTROL_ALLOW_ORIGIN:"*"。

新手大概看不出来这有什么问题,这就是对跨域的误解。

我以为项目部署在远程,地址是121.123.123.8,而我的本机地址是142.11.32.11(瞎写的,突出不一致),于是我就以为这就是跨域访问了,毕竟地址都不一样了。

然而,跨域的含义不是这样,跨域是指“在同一个页面中协议、域名、端口三者存在不一致”,我一直突出协议、域名、端口不一致,忽略了最关键条件“在同一个页面中”,因此凡是单接口请求一般是测不出跨域的,postman、浏览器等其他接口测试工具是没有跨域问题的,他们根本就没有页面差异或者说根本没有页面概念。

前后端之所以有跨域问题,是因为前端也是运行在一个http容器里面的,整过前端项目的都知道,运行项目的时候也是通过localhost:8080进行访问的,这就是“当前页面url”。

如果在其中请求localhost:8081下的一个接口,此时就是“同一个页面中端口不一致”,就发生了跨域。

另外,有大佬说postman的较新版本是模拟前端环境进行测试的,因此跨域也是可以测出来的(也有另一个大佬说postman不存在跨域问题)水平有限,具体的我也没测出来。

更新

本来好好的,结果前端同学依旧发生了跨域,而nginx配置正常。

整了一整天,最终终于解决。

在nginx对OPTIONS请求进行额外处理:

在跨域过程中(PUT、DELETE、发送JSON数据请求),会先发送一次预检OPTIONS请求,然而不知道为什么OPTIONS没有通过上图所示红框的上半部分(印象中OPTIONS似乎为了节省资源,省略了很多东西,所以可能没有执行该部分)

顺便提供一下其他相关资料。

忽略掉OPTIONS请求:

大佬参考的文章

阮一峰跨域详解,强推

0 人点赞