问题背景:
Same Origin Policy(SOP同源策略):具有相同的Origin即拥有相同的协议、主机地址及端口。
目的是防止某个文档或者脚本从多个不同源的地址装载(其他站点转载内容不安全)。
CORS简介
跨域资源共享(CORS:Cross-origin resource sharing):它允许浏览器向跨源服务器发出XMLHTTP Request请求,从而克服了AJAX只能同源使用的限制。CORS需要浏览器和服务器同时支持,它的通信由浏览器自动完成,不需要用户参与。CORS通信的关键在于服务器,服务器需要实现CORS接口。
CORS请求分两类
浏览器发出的CORS简单请求,只需要在头信息中增加一个Origin字段。
-
简单请求(simple request):HEAD、GET、POST请求,并且HTTP的头信息仅为以下几种字段:
Accept、Accept-Language、Content-Language、Last-Event-ID、
Content-Type(仅限3个值:application/x-www-form-urlencoded、multipart/form-data、text/plain) -
非简单请求(not-so-simple):不在简单请求范围的为非简单请求。
浏览器发出非简单请求会在正式通信之前增加一次OPTIONS查询请求,称为“预检”请求(preflight)。浏览器先访问服务器,当前网页所在域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会正式发出XMLHttpRequest请求,否则报错。
详解响应头
-
Access-Control-Allow-Origin(必填):请求时Origin字段的具体值或者*(表示接受任意域名的请求)
-
Access-Control-Allow-Methods(必填):逗号分割的一个具体字符串或者*,表示服务器支持的所有跨域请求方法。返回的是所有支持的方法而不单是浏览器请求的那个方法,避免多次“预检”请求。
-
Access-Control-Expose-Headers(可选):CORS请求XMLRequest对象的getResponseHeader方法只能拿到6个基本字段(Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma)如果需要拿到其他字段,就必须在这里指定。
-
Access-Control-Allow-Credentials(可选):布尔值(表示是否允许发送Cookie,默认false),对服务器有特殊要求的请求(PUT、DELETE、Content-Type的类型为application/json)时这个值只能为true,如果服务器不需要浏览器发送Cookie,删除即可。
-
Access-Control-Max-Age(可选):指定本次预检请求的有效期,单位为秒,有效期内不用再发预检请求。如果发现开发中每次请求都是2条(一次是OPTIONS,一次是正常请求)那么就需要配置此字段,避免每次都发出预检请求。
三种解决方案:
-
全局配置,实现WebMvcConfigurer接口的addCorsMappings方法Github示例代码
-
全局Filter配置,实现javax.servlet.Filter接口的doFilter方法Github示例代码
-
@CrossOrigin注解,类型@RequestMapping注解的使用(最小粒度的控制,精确到单个请求级别)
一般使用前两种全局配置即可,同时配置就近原则生效。