协议(protocol),主机(host)和端口号
前端
服务器的协议,IP和端口和后端
服务器不一样
,就产生了跨域CORS
是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)克服了AJAX只能同源使用的限制
只要同时满足以下两大条件,就属于简单请求
基本流程
Origin
字段举例
Origin
字段协议 + 域名 + 端口
)。服务器根据这个值,决定是否同意这次请求GET /cors HTTP/1.1
Origin: http://api.bob.com
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: FooBar
Content-Type: text/html; charset=utf-8
上面的头信息之中,有三个与CORS请求相关的字段,都以Access-Control-
开头
application/json
"预检"请求
举例
PUT
,并且发送一个自定义头信息X-Custom-Header
OPTIONS /cors HTTP/1.1
Origin: http://api.bob.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
OPTIONS
,表示这个请求是用来询问的。头信息里面,关键字段是Origin
,表示请求来自哪个源HTTP方法
头信息字段
服务器收到"预检"请求以后,检查了Origin
、Access-Control-Request-Method
和Access-Control-Request-Headers
字段以后,确认允许跨源请求,就可以做出回应
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain
有效期
,单位为秒XMLHttpRequest cannot load http://api.alice.com.
Origin http://api.bob.com is not allowed by Access-Control-Allow-Origin.
Origin
头信息字段Access-Control-Allow-Origin
头信息字段"预检"请求之后,浏览器的正常CORS请求
PUT /cors HTTP/1.1
Origin: http://api.bob.com
Host: api.alice.com
X-Custom-Header: value
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
服务器正常的回应
Access-Control-Allow-Origin: http://api.bob.com
Content-Type: text/html; charset=utf-8
RequestMapping修饰的方法
和Controller类上
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CrossOrigin {
@AliasFor("origins")
String[] value() default {};
@AliasFor("value")
String[] origins() default {};
/**
* @since 5.3
*/
String[] originPatterns() default {};
String[] allowedHeaders() default {};
String[] exposedHeaders() default {};
RequestMethod[] methods() default {};
String allowCredentials() default "";
long maxAge() default -1;
}
@CrossOrigin属性介绍
默认配置是“*”
默认为“*”
表示允许所有的请求头开启该选项时origin不允许设置为“*”
1800s
,在缓存时间内同一请求不需要“预检”请求@CrossOrigin注解比较适用于较细粒度的跨域控制
@Configuration
//创建WebConfig类实现WebMvcConfigurer接口,通过CorsRegistry设置跨域信息
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("https://domain2.com")
.allowedMethods("PUT", "DELETE")
.allowedHeaders("header1", "header2", "header3")
.exposedHeaders("header1", "header2")
.allowCredentials(true).maxAge(3600);
}
}
在跨域过滤器里配置一下跨域头部,* 是通配符即允许所有
@Configuration
public class GatewayCorsConfiguation {
@Bean
public CorsFilter corsFilter(){
// 初始化cors配置对象
CorsConfiguration configuration = new CorsConfiguration();
// 允许使用cookie,但是使用cookie是addAllowedOrigin必须是具体的地址,不能是*
configuration.setAllowCredentials(true);
// configuration.addAllowedOrigin("*");
configuration.addAllowedOrigin("http://manage.leyou.com");
//允许的请求方式,get,put,post,delete
configuration.addAllowedMethod("*");
//允许的头信息
configuration.addAllowedHeader("*");
//初始化cors的源对象配置
UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource();
corsConfigurationSource.registerCorsConfiguration("/**",configuration);
//返回新的CorsFilter.
return new CorsFilter(corsConfigurationSource);
}
}
@WebFilter("/*")
public class CrosFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) servletResponse;
HttpServletRequest request =(HttpServletRequest) servletRequest;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, HEAD");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "access-control-allow-origin, authority, content-type, version-info, X-Requested-With");
// 非预检请求,放行即可,预检请求,则到此结束,不需要放行
if(!request.getMethod().equalsIgnoreCase("OPTIONS")){
filterChain.doFilter(servletRequest, servletResponse);
}
}
}