SpringBoot 配置 跨域支持
👆关注微信公众号,获取更多编程内容
跨域资源共享(CORS,请求协议,请求地址,请求端口三者必须相同才是同一服务器,否则都要进行跨域操作)标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站有权限访问哪些资源。另外,规范要求,对那些可能对服务器数据产生副作用的 HTTP 请求方法(特别是 GET 以外的 HTTP 请求,或者搭配某些 MIME 类型的 POST 请求),浏览器必须首先使用 OPTIONS 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨域请求。服务器确认允许之后,才发起实际的 HTTP 请求。在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份凭证(包括 Cookies 和 HTTP 认证相关数据)。
常见的CORS的HTTP头
其根本是在请求响应结果中添加响应头,来表名服务支持CORS,因此常见的CORS头如下:
名称 | 示例 | 作用 |
---|---|---|
Access-Control-Allow-Origin | https://www.zhoutao123.com | 表明它允许"www.zhoutao123.com"发起跨域请求 |
Access-Control-Max-Age | 3628800 | 表明在3628800秒内,不需要再发送预检验请求 |
Access-Control-Allow-Methods | GET,PUT, DELETE | 允许GET、PUT、DELETE的外域请求 |
Access-Control-Allow-Headers | content-type | 允许跨域请求包含content-type头 |
CORS执行流程
CORS在首次请求跨域服务器之前,都要进行预检请求 ,会首先发送一个OPTIONS请求检查是否支持CORS,待服务器响应之后,在进行后续的操作,具体流程图下,当然并不是每个请求都会发送OPTIONS请求,在确认支持CORS之后,浏览器会把验证结果缓存下来,缓存的有效时间可以通过 Access-Control-Max-Age
来控制:
预检请求重定向
大多数浏览器不支持针对于预检请求的重定向。如果一个预检请求发生了重定向,浏览器将报告错误:
The request was redirected to 'https://example.com/foo', which is disallowed for cross-origin requests that require preflight
Request requires preflight, which is disallowed to follow cross-origin redirect
CORS 最初要求该行为,不过在后续的修订中废弃了这一要求。不过我们还是尽量不要对OPTIONS预检请求做重定向处理.
- 注意:因为CORS在发送真正的请求之前会发送OPTIONS请求,以此来验证服务器是否支持跨域,此次预检请求不携带任何真正请求的参数,当前也不包括我们设定的token参数,因此如果你的Spring应用或者其他应用在拦截器上做了验证,请注意不要拦截OPTIONS请求,否则CORS支持会开启失败.
SpringBoot开启CORS
非全局配置
So that the RESTful web service will include CORS access control headers in its response, you just have to add a @CrossOrigin annotation to the handler method
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CrossOrigin {
//允许跨域的服务器
@AliasFor("origins")
String[] value() default {};
//和上面是一样的 AliasFor
@AliasFor("value")
String[] origins() default {};
//允许头部
String[] allowedHeaders() default {};
String[] exposedHeaders() default {};
/**
* The list of supported HTTP request methods.
* <p>By default the supported methods are the same as the ones to which a
* controller method is mapped.
*/
RequestMethod[] methods() default {};
String allowCredentials() default "";
/**
* The maximum age (in seconds) of the cache duration for preflight responses.
* <p>This property controls the value of the {@code Access-Control-Max-Age}
* response header of preflight requests.
* <p>Setting this to a reasonable value can reduce the number of preflight
* request/response interactions required by the browser.
* A negative value means <em>undefined</em>.
* <p>By default this is set to {@code 1800} seconds (30 minutes).
*/
long maxAge() default -1;
}
只要在SpringBoot的Mapper()接口中添加并配置此注解即可
//根据CrossOrigin的注释可以再请求参数的不存在的时候,CORS支持的方法和Mapper支持的方法一致
@CrossOrigin(origins = "http://localhost:9000")
@GetMapping("/test")
public Greeting greeting(@RequestParam(required=false, defaultValue="World") String name) {
System.out.println("==== in tesing ====");
return "SUCCESS";
}
全局配置
在大量接口需要开启CORS支持的时候,上面的方式显然不适合操作,因此Spring提供了全局配置CORS支持的方式。
@Bean
@SuppressWarnings("deprecation")
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
@Override
public void addCorsMappings(CorsRegistry registry) {
log.info("CORS 配置参数 origins = {} url = {}", allowedOrigins, allowedUrl);
registry
.addMapping("/**")
.allowedMethods("GET", "POST", "PATCH", "DELETE", "PUT", "OPTIONS")
.allowedOrigins("http://localhost:9090");
}
};
}