根因分析
造成跨域的根本原因是,两个资源的协议、域名、子域名、端口不同,而且是只要有一个不同,这种情况下所进行的访问行动都是跨域的。而出于安全性的考虑,浏览器通常会限制跨域访问,不允许跨域请求资源,这是浏览器的同源策略。但是需要非常明确一点的是,跨域请求被禁止,并不是浏览器拦截了跨域请求,导致请求发不出去,而是请求发到了服务端,在服务端的过滤器 filter 中进行了校验逻辑,本质就是根据Request Headers中Origin属性的值,与服务器端的 CORS Configuration配置中允许的源进行比较,如果Request Headers中Origin属性的值存在于服务器允许的源的列表中,则请求允许通过,继续往下请求,否则请求被拦截,返回403错误。
注意:网上看到很多说是请求到了服务端,服务端也返回了请求处理的结果,只是浏览器把结果拦截了的说法,我认为是不正确的,因为请求根本没有到我们要调用的方法中,就已经被过滤器拦截了。
解决方案
跨域资源共享(Cross Origin Resource Share)是一种允许一个网页上的JavaScript向另一个域中发出 AJAX 请求机制 。CORS机制的工作原理通过添加一些特定的HTTP头部标识,使得浏览器被告知下载的资源应当被允许给定的域(或者所有的域)进行Web请求。
可以对如下的ResponseHeaders参数进行设置,以达到跨域资源请求。
Access-Control-Allow-Origin :指定授权域来进行跨域请求,如果此项没有限制,使用*作为参数值。
Access-Control-Allow-Credentials :指定跨域请求是否需要验证。
Access-Control-Expose-Headers :指示哪一种头部标识可以被安全的暴露(公开)。
Access-Control-Max-Age :指定预检请求的最大缓存时间。
Access-Control-Allow-Methods :指定进行跨域请求时使用的方法。
Access-Control-Allow-Headers :指定实际的请求过程中哪些头部标识可以使用。
代码示例

有两种方式都可以解决这个跨域报错问题:
- 第一种如上自定义一个CorsFilter,在代码中自定义CorsConfiguration。
- 在controller层面添加@CrossOrigin注解即可,添加这个注解后框架会自动帮我们默认生成一个配置类CorsConfiguration,如下图:

框架自动生成的CorsConfiguration
浏览器三模块参数说明
在浏览器的一个常规请求中,通常包含三部分 General ,Response Headers,Request Headers。
#请求服务器路径
Request URL:
#请求方法Get
Request Method: GET
#请求响应码
Status Code: 200
#服务器IP+ 端口号
Remote Address: 10.0.245.245:443
#访问来源策略
Referrer Policy: no-referrer-when-downgrade
Response Headers
#证书验证
access-control-allow-credentials: true
#允许访问的源
access-control-allow-origin:
#采用gzip压缩,压缩效果最好
content-encoding: gzip
content-type: application/json;charset=UTF-8
#返回时间
date: Thu, 02 Jul 2020 02:07:19 GMT
#返回状态码
status: 200
strict-transport-security: max-age=15724800; includeSubDomains
vary: Accept-Encoding, Origin, Access-Control-Request-Method, Access-Control-Request-Headers
x-svc: cs-backend-test-rbs-service-http
Request Headers
#指定客户端能够接收的内容类型
Accept: application/json, text/plain, */*
#授权值,服务器根据这个值解析出token
Authorization: Bearer ae7a11114-193f-4122-a615-d465807f615c
#源
Origin:
#访问来源
Referer:
#post请求下会存在这个值,指明消息主体数据的编码方式,也就是传到后台参数数据的编码方式
Content-Type: application/json;charset=UTF-8
#安全获取模式
Sec-Fetch-Mode: cors
#token值
token: ae7a11114-193f-4122-a615-d465807f615c
#浏览器信息
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.36 Safari/537.36
总结
1.两个资源的协议、域名、子域名、端口不同,这种情况下所进行的访问行动都是跨域的。而出于安全性的考虑,浏览器通常会限制跨域访问,不允许跨域请求资源。
2.跨域只存在于浏览器端,是受到了浏览器的同源策略的限制。
3.CORS,跨域资源共享(Cross Origin Resource Share)是一种允许一个网页上的JavaScript向另一个域中发出AJAX请求机制。
4.跨域请求被禁止,并不是浏览器拦截了跨域请求,导致请求发不出去,而是请求发到了服务端,在服务端的过滤器filter中进行了校验逻辑,本质就是根据Request Headers中Origin属性的值,与服务器端的CorsConfiguration配置中允许的源进行比较,如果Request Headers中Origin属性的值存在于服务器允许的源的列表中,则请求允许通过,继续往下请求,否则请求被拦截,返回403错误。
5.之所以会跨域,是因为受到了同源策略的限制,同源策略要求源相同才能正常进行通信,即协议、域名、端口号都完全一致。