先说明一个坑。在跨域的情况下,浏览器针对复杂请求,会发起预检OPTIONS请求。如果服务端对OPTIONS进行拦截,并返回非200的http状态码。浏览器一律提示为cors error。
一、了解跨域
1.1 同源策略
浏览器的同源策略(Same-Origin Policy),用于限制网页中的JavaScript代码与来自不同源的资源进行交互。
同源策略的规则包括
- 协议相同
- 域名或主机地址相同
- 端口相同
下图为是否同源的示例
1.2 跨域资源共享
1.2.1 概念
跨域资源共享(Cross-Origin Resource Sharing,CORS)是一种机制,为了绕过浏览器的同源策略(Same-Origin Policy)而设计的,它允许网页从不同源(域名、协议、端口)获取或发送HTTP请求,以实现跨域数据交换。
CORS将HTTP请求分为两类,如果详细了解,请查阅跨域资源共享-W3C
- 简单请求
- 请求方式
- 特定的Content-Type值
- text/plain
- multipart/form-data
- application/x-www-form-urlencoded
- 请求头Accept, Accept-Language, Content-Language
- 预检请求
- 当浏览器检测到一个跨域请求不符合”简单请求”的条件时,它会自动发送一个预检请求以获得服务器的授权。
- 非简单请求的请求方式
- 非简单请求的Content-Type值
- 非简单请求的请求头
1.2.2 服务器
服务器通过在响应中包含相应的CORS头部来授权或拒绝请求。常见的CORS头部包括:
Access-Control-Allow-Origin
:指定哪些源可以访问资源。Access-Control-Allow-Methods
:指定允许的HTTP方法。Access-Control-Allow-Headers
:指定允许的自定义HTTP头部。Access-Control-Allow-Credentials
:指定是否允许发送凭据,如Cookie。Access-Control-Max-Age
:时间单位为秒。指定预检请求的缓存时间,减少后续请求的预检请求次数。
二、SpringBoot示例配置
SpringBoot配置跨域三种方式,启动项目进行测试。访问http://127.0.0.1:4321/
源码地址
2.1 局部注解
1 2 3 4 5
| @PostMapping("/annotation") @CrossOrigin public String annotation() { return "注解实现跨域"; }
|
2.2 第一种全局
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
@Bean public CorsFilter first() { CorsConfiguration config = new CorsConfiguration(); config.addAllowedOriginPattern("*"); config.setAllowCredentials(true); config.addAllowedHeader("*"); config.addAllowedMethod("GET"); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", config); return new CorsFilter(source); }
|
2.3 第二种全局
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| @Bean public FilterRegistrationBean cross() { FilterRegistrationBean registrationBean = new FilterRegistrationBean(); registrationBean.setFilter((servletRequest, servletResponse, filterChain) -> { HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse; HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
httpServletResponse.setHeader("Access-Control-Allow-Origin", httpServletRequest.getHeader("origin")); httpServletResponse.setHeader("Access-Control-Allow-Headers", "*"); httpServletResponse.setHeader("Access-Control-Allow-Methods", "*"); httpServletResponse.setHeader("Access-Control-Allow-Credentials", "true"); if (httpServletRequest.getMethod().equalsIgnoreCase("options")) { httpServletResponse.setStatus(200); return; } filterChain.doFilter(servletRequest, servletResponse); }); registrationBean.setName("CrossOrigin"); registrationBean.addUrlPatterns("/*"); registrationBean.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE);
return registrationBean; }
|
2.4 第三种全局
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @Component public class SystemWebMvcConfigurer extends WebMvcConfigurationSupport {
@Override public void addCorsMappings(CorsRegistry registry) { registry .addMapping("/**") .allowCredentials(true) .allowedOriginPatterns("*") .allowedHeaders("*") .allowedMethods("*"); } }
|