言成言成啊 | Kit Chen's Blog

理解跨域及SpringBoot的跨域配置

发布于2023-08-26 22:12:37,更新于2024-06-27 19:34:30,标签:java http  文章会持续修订,转载请注明来源地址:https://meethigher.top/blog

先说明一个坑。在跨域的情况下,浏览器针对复杂请求,会发起预检OPTIONS请求。如果服务端对OPTIONS进行拦截,并返回非200的http状态码。浏览器一律提示为cors error。

一、了解跨域

1.1 同源策略

浏览器的同源策略(Same-Origin Policy),用于限制网页中的JavaScript代码与来自不同源的资源进行交互。

同源策略的规则包括

  1. 协议相同
  2. 域名或主机地址相同
  3. 端口相同

下图为是否同源的示例

1.2 跨域资源共享

1.2.1 概念

跨域资源共享(Cross-Origin Resource Sharing,CORS)是一种机制,为了绕过浏览器的同源策略(Same-Origin Policy)而设计的,它允许网页从不同源(域名、协议、端口)获取或发送HTTP请求,以实现跨域数据交换。

CORS将HTTP请求分为两类,如果详细了解,请查阅跨域资源共享-W3C

  1. 简单请求
    • 请求方式
      • GET
      • POST
      • HEAD
    • 特定的Content-Type值
      • text/plain
      • multipart/form-data
      • application/x-www-form-urlencoded
    • 请求头Accept, Accept-Language, Content-Language
  2. 预检请求
    • 当浏览器检测到一个跨域请求不符合”简单请求”的条件时,它会自动发送一个预检请求以获得服务器的授权。
    • 非简单请求的请求方式
    • 非简单请求的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
/**
* 方式一
*
* @see <a href="https://blog.csdn.net/qq_37651252/article/details/106630443">跨域配置方式一</a>
*/
@Bean
public CorsFilter first() {
CorsConfiguration config = new CorsConfiguration();
//允许所有域名进行跨域调用
//config.addAllowedOrigin("*");//springboot2+不适用该方法
config.addAllowedOriginPattern("*");
//允许跨越发送cookie
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;

//OPTIONS请求用于跨域时,浏览器用于预检内容,一般响应OPTIONS请求正常即可。反正还是要具体情况具体实现

//httpServletResponse.setHeader("Access-Control-Allow-Origin", "*");
//有时候直接用*会导致范围过大,浏览器出于安全考虑,有时候会不认*这个操作,因此可以使用如下代码,间接实现允许跨域
httpServletResponse.setHeader("Access-Control-Allow-Origin", httpServletRequest.getHeader("origin"));
//响应头设置
httpServletResponse.setHeader("Access-Control-Allow-Headers", "*");
//响应类型
httpServletResponse.setHeader("Access-Control-Allow-Methods", "*");
//允许跨越发送cookie
httpServletResponse.setHeader("Access-Control-Allow-Credentials", "true");
if (httpServletRequest.getMethod().equalsIgnoreCase("options")) {
//在携带头特殊的请求头并且非同源的条件下,会发送预检请求。
//通过响应头告诉预检请求,我是支持跨域的。并且返回状态码是200
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("*");
}
}
发布:2023-08-26 22:12:37
修改:2024-06-27 19:34:30
链接:https://meethigher.top/blog/2023/sb-crossorigin/
标签:java http 
付款码 打赏 分享
Shift+Ctrl+1 可控制工具栏