文章目录
- 什么是跨域
- 解决方案
- @CrossOrigin注解
- 实现WebMvcConfigurer接口
- CorsFilter过滤器
- 如何选择?
前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。
Talk is cheap , 先看代码。
在Springboot项目中新建一个测试接口,端口号默认8080:
@RestController
@RequestMapping("test")
public class TestController {
@GetMapping("1")
public String test1(){
System.out.println("1");
return "111111111";
}
}
再新建一个HTML页面,在页面内访问上述接口:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script>
function cors() {
$.get('http://localhost:9090/test/1', function(data) {
alert(data)
});
}
</script>
</head>
<body>
<button onclick="cors()">CORS</button>
</body>
</html>
从Idea中打开,并在浏览器访问, 点击CORS按钮,你猜会发生什么?
是的,你猜对了,浏览器控制台会出现如下提示,就是告诉你跨域了。
cors.html:1 Access to XMLHttpRequest at 'http://localhost:9090/test/1' from origin 'http://localhost:63342' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
什么是跨域
介绍跨域之前要介绍一下同源策略,什么是同源策略呢?
同源策略是浏览器的一种安全策略,用于限制一个网页文档或脚本如何与其他源的资源进行交互。同源策略的核心思想是:网页文档或脚本只能与加载它们的同一个源下的资源进行交互,而不能与不同源的资源直接进行数据交换。
同源策略有如下3点要求:
- 协议相同:两个页面的协议必须相同(如都是
https
)。 - 域名相同:两个页面的域名(包括子域名)必须相同。
- 端口相同:如果指定了端口号,两个页面的端口号必须相同。
举个例子:
- 如果页面 A 加载自
https://www.example.com
,那么它只能与https://www.example.com
下的资源进行交互,比如可以通过 JavaScript 发送 AJAX 请求。 - 页面 A 不能直接与
https://api.example.net
或http://sub.example.com
这些不同源的资源进行交互,因为它们的协议、域名或端口不同。
为什么要有同源策略?
如果没有同源策略,网站A就可以访问网站B的Cookie,Cookie中可能会存在用户的token或者其他敏感信息,通过这些敏感信息可能会发送一些伪请求到网站B,从而窃取一些数据。这就相当于你们家什么安全措施都不做,别人想进就进,那可不丢家吗。
跨域或者叫跨域资源共享(Cross-origin resource sharing, CORS) :当浏览器访问不同源的网站时,就会产生跨域问题。
为了让不同源之间的能够访问,就要解决跨域问题。
解决方案
在Springboot中通常有3种方式:
- 使用**@CrossOrigin注解**
- 实现WebMvcConfigurer接口
- 使用CorsFilter过滤器
@CrossOrigin注解
@CrossOrigin注解可以作用于类或者方法级别,当作用于类级别时,表示该类中所有方法都可以实现跨域访问。当应用于方法级别时,表示该方法可以实现跨域访问。
举个例子:
@RestController
@RequestMapping("test")
public class TestController {
@CrossOrigin(origins = "http://localhost:63342") // 仅允许来自localhost:63342的请求跨域
@GetMapping("1")
public String test1(){
System.out.println("1");
return "111111111";
}
}
@CrossOrigin注解有如下属性:
-
origins
:允许访问的源列表。可以指定一个或多个 URL,或者使用*
来允许所有源。注意,如果allowCredentials
设置为true
,则不能使用*
,必须明确指定源。 -
methods
:允许的方法列表,如GET
、POST
、PUT
等。同样,也可以使用*
来允许所有方法。 -
allowedHeaders
:请求中允许的头列表。使用*
可以允许所有头。 -
exposedHeaders
:响应中暴露给客户端的头列表。这些头会被添加到Access-Control-Expose-Headers
响应头中。 -
allowCredentials
:是否允许发送 cookies。如果设置为true
,浏览器将允许前端 JavaScript 访问响应中设置的 Cookies 和 HTTP 认证信息。这个选项和配置的域建立了很高的信任度,不过呢,也因为暴露了像 Cookies 和 CSRF 令牌这类敏感的用户特定信息,增加了应用程序被攻击的可能性。 当allowCredentials
为true
时,origins
不能设置为*
。 -
maxAge
:预检请求的结果可以被缓存多久(以秒为单位)。这可以减少不必要的预检请求,提高性能。 -
originPatterns
:Spring 5.3 版本开始新增的属性。允许使用通配符模式来定义允许访问的域名。比如,originPatterns={https://*.domain1.com}
,就是可以匹配以domain1.com
结尾的网站。 -
allowPrivateNetwork
:Spring 5.3.32 版本开始新增的属性。是否允许来自私有网络地址的请求通过跨域请求。
实现WebMvcConfigurer接口
WebMvcConfigurer
接口是Spring MVC的一个配置接口,通过它可以自定义配置Spring MVC的行为,包括但不限于视图解析器、静态资源处理、消息转换器、拦截器、跨域等。
只要实现WebMvcConfigurer接口重写addCorsMappings方法即可。
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // 对所有路径生效
.allowedOriginPatterns("*") // 允许源地址的通配符
// .allowedOrigins("http://localhost:63342") // 允许源地址http://localhost:63342
.allowCredentials(true) // 是否允许发送Cookie
.allowedMethods("GET", "POST", "DELETE", "PUT") // 允许的请求方法
.allowedHeaders("*"); // 允许的请求头
}
}
CorsRegistry
是一个用于配置跨域的工具类。
CorsRegistry
类中的属性和@CrossOrigin
注解中的跨域属性基本相同,作用也是一样的,这里不做过多介绍。
CorsFilter过滤器
CorsFilter
过滤器,见名知意就是一个用于处理跨域请求的过滤器。具体用法如下:
@Configuration
public class CorsFilterConfig {
@Bean
public CorsFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOrigin("http://localhost:63342");
config.setAllowCredentials(true);
config.addAllowedMethod("*");
config.addAllowedHeader("*");
// config.addAllowedOriginPattern("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
// 匹配路径
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
看它的用法是不是特别熟悉,是的,没错,它也和@CrossOrigin
注解中的跨域属性基本相同。
如何选择?
既然@CrossOrigin
注解、WebMvcConfigurer
配置类、CorsFilter
过滤器都能解决跨域问题,那使用哪个好呢?
先来看一下它们之间的区别:
WebMvcConfigurer
:用于全局配置CORS策略,适合需要全局配置的场景。CorsFilter
:可以精细配置CORS策略,并适用于对不同路径设置不同的CORS策略。@CrossOrigin
:用于局部配置,非常适合单个Controller或方法需要不同的CORS策略的情况。
在实际项目中,可以根据需求选择合适的方式来解决跨域问题。如果项目中的跨域需求较为统一,且希望有一个全局性的解决方案,那么WebMvcConfigurer
可能是一个不错的选择。如果需要对跨域请求进行更细粒度的控制,或者项目中的跨域需求较为分散,那么CorsFilter
或@CrossOrigin
可能更适合。
所以,没有好不好,只有合不合适,合适你的就是最好的。
以上在Springboot中解决跨域的三种方式其实都是对CorsConfiguration
跨域配置类的封装,感兴趣的可以看一看CorsConfiguration
跨域配置类。