CORS是一个W3C标准,全称是“跨域资源共享”(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。
由于浏览器同源策略(同源策略,它是由Netscape提出的一个著名的安全策略。现在所有支持JavaScript 的浏览器都会使用这个策略。所谓同源是指,域名,协议,端口相同。),凡是发送请求url的协议、域名、端口三者之间任意一与当前页面地址不同即为跨域。
JSONP 是 JSON with padding(填充式 JSON 或参数式 JSON)的简写。JSONP实现跨域请求的原理简单的说,就是动态创建 < script >标签,然后利用< script >的src 不受同源策略约束来跨域获取数据。
JSONP 由两部分组成:回调函数和数据。回调函数是当响应到来时应该在页面中调用的函数。回调函数的名字一般是在请求中指定的。而数据就是传入回调函数中的 JSON 数据。
这里不详讲这个,有兴趣的话请看下面这篇文章:
轻松搞定JSONP跨域请求
为了解决浏览器同源问题,W3C 提出了跨源资源共享,即 CORS(Cross-Origin Resource Sharing)。
主要使用@CrossOrigin注解实现,源码如下:
...
@Target({ElementType.METHOD, ElementType.TYPE})//可作用于方法,类上
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CrossOrigin {
...
@AliasFor("origins")//允许可访问的域列表
String[] value() default {};
...
long maxAge() default -1L;//准备响应前的缓存持续的最大时间(以秒为单位)。
}
@CrossOrigin(origins = "http://localhost:8080",maxAge = 3600)
@RequestMapping("/test")
String test() {
...
}
@CrossOrigin(origins = "http://localhost:8080",maxAge = 3600)
@RestController
public class UserController {
...
}
/**
* @author Macky
* @Title class WebMvConfig
* @Description: TODO
* @date 2019/8/2 13:52
*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE")
.maxAge(3600)
.allowCredentials(true);
}
}
还可以添加Filter,指定CORS规则,并指定对哪些接口有效:
@Bean
public FilterRegistrationBean corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("http://localhost:8080");
config.addAllowedOrigin("null");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config); // CORS 配置对所有接口都有效
FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
bean.setOrder(0);
return bean;
}
Spring cors的校验都是交给DefaultCorsProcessor类中的processRequest()方法实现的,核心代码如下:
public boolean processRequest(@Nullable CorsConfiguration config, HttpServletRequest request, HttpServletResponse response) throws IOException {
if (!CorsUtils.isCorsRequest(request)) {//1.判断是否有“Origin”的header,,有的话
return true;
} else {
ServletServerHttpResponse serverResponse = new ServletServerHttpResponse(response);
if (this.responseHasCors(serverResponse)) {//2.判断response中header是否有“Access-Control-Allow-Origin”
logger.trace("Skip: response already contains \"Access-Control-Allow-Origin\"");
return true;
} else {
ServletServerHttpRequest serverRequest = new ServletServerHttpRequest(request);
if (WebUtils.isSameOrigin(serverRequest)) {//3.判断是否同源
logger.trace("Skip: request is from same origin");
return true;
} else {
boolean preFlightRequest = CorsUtils.isPreFlightRequest(request);
if (config == null) {//4.是否配置了 CORS 规则,如果没有配置,且是预检请求,则拒绝该请求,如果没有配置,且不是预检请求,则交给负责该请求的类处理。如果配置了,则对该请求进行校验。
if (preFlightRequest) {
this.rejectRequest(serverResponse);
return false;
} else {
return true;
}
} else {
return this.handleInternal(serverRequest, serverResponse, config, preFlightRequest);
}
}
}
}
}
SpringBoot配置Cors解决跨域请求问题