前言
现在开发基本上都是前后端分离模式,跨域问题的处理似乎已经成为一件很自然的事情了,可以前端解决、也可以后端解决、用Nginx解决。我也不咋会前端,就从后端角度总结一下自己之前在开发过程中是如何处理跨域问题的。
什么是跨域问题
浏览器基于安全方面考虑,使用同源策略。
同源策略
怎样才算是同源?
协议+域名+端口都必须相同
最开始的同源策略用于限制Cookie的访问,只有同源的网页才能访问某网页设置的Cookie。
cookie目的是让服务端知道谁发出的这次请求。服务端验证通过后会在响应头加入Set-Cookie字段,下次再发起请求的时候,浏览器会自动将cookie附加在HTTP请求的头字段Cookie中,服务端就能知道这个用户已经登录过了。
比如现在我在访问A网址,登录成功,然后我又访问B网址,如果没有同源策略限制,B网址可以利用浏览器自动将cookie附加在HTTP请求的头字段Cookie中再去向A网址发起请求,就假装成了我本人去进行操作。这就是CSRF(Cross Site Request Forgery,跨站请求伪造)。
PS:即使有同源策略也未必是安全的,cookie是明文的,有设置httpOnly让前端无法操作cookie、设置secure保证在https的加密通信中传输以防止被拦截等方式保障安全。
现在的同源策略限制的更多了:
- Cookie、LocalStorage和IndexDB无法获取
- DOM无法获得
- 请求的响应被拦截
跨域不是请求发不出去,请求是可以发出去的,后端可以正常接收前端发送的数据,但是浏览器会拦截后端返回给前端的结果,浏览器为了防止非同源的请求拿到后端的返回数据。
CORS
CORS是一个W3C标准,处理跨域问题的标准做法。允许浏览器向跨源服务器发出XMLHttpRequest请求,从而克服了只能发送同源请求的限制。
CORS实现机制:
浏览器发起跨域HTTP请求,浏览器会自动将当前资源的域添加在请求头中一个叫Origin的Header中。
有三个标签本身就是允许跨域加载资源的:
<img src=>
<link href=>
<script src=>
跨域有两种请求:
简单请求:
请求方法只能是HEAD,GET,POST
主动设置的头信息不能超过以下字段:Accept,Accept-Language,Content-Language,Last-Event-ID,Content-Type(只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain)
非简单请求:不能同时满足简单请求的2个条件
对于简单请求:
- 浏览器在请求头信息里加一个Origin字段,表明来源。
- 服务器返回的头部包含Access-Control-Allow-Origin并包含Origin
- 如果需要携带Cookie,返回头需要有Access-Cotrol-Allow-Credentials:true
服务器在返回头信息里设置:
Access-Control-Allow-Origin: xxx.xxx.xxx.xxx:xxx
需要携带Cookie:
Access-Control-Allow-Credentials: true (小写!)
如果想匹配所有的Origin并且不带Cookie:
Access-Control-Allow-Origin: *
如果想匹配所有的Origin并且不带Cookie:
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: 请求的Origin(request获取后填入)
true和*是不能同时存在的啊!切记!
Access-Control-Allow-Origin 允许http://www.xxx.com发起跨域请求
Access-Control-Max-Age 设置在多少秒不需要再发送预校验请求
Access-Control-Allow-Methods 设置允许跨域请求的方法
Access-Control-Allow-Headers 允许跨域请求包含content-type
Access-Control-Allow-Credentials 设置允许Cookie
后端配置方案
SpringBoot
F1: 使用@CrossOrigin(“http://xxx.xxx.xxx.xxx:xx”)注解,略,每个都配太累了。
F2:CORS全局配置,实现WebMvcConfigurer接口
@Configuration
public class CorsConfig implem