Spring中的跨域资源共享(CORS)配置:@CrossOrigin与CorsFilter
开场白
各位小伙伴,大家好!今天咱们来聊聊Spring中非常实用的CORS(跨域资源共享)配置。在现代Web开发中,前后端分离已经成为主流,而跨域问题也随之而来。想象一下,你的前端应用跑在一个域名上,而后端API却在另一个域名上,浏览器出于安全考虑,默认是不允许这种跨域请求的。这时候,CORS就派上用场了!
为了让大家更好地理解CORS,今天我们通过两个主角——@CrossOrigin
注解和CorsFilter
过滤器——来深入探讨如何在Spring中优雅地解决跨域问题。准备好了吗?让我们开始吧!
什么是CORS?
CORS(Cross-Origin Resource Sharing,跨域资源共享)是一种机制,它允许一个域名下的资源被另一个域名下的页面访问。浏览器会自动在HTTP请求中添加一些额外的头信息,服务器则需要在响应中返回特定的头信息来告诉浏览器是否允许跨域请求。
简单来说,CORS就是浏览器和服务器之间的一种“协议”,用来决定是否允许跨域请求。如果没有CORS,浏览器会直接阻止跨域请求,导致前端无法正常调用后端API。
CORS的工作原理
-
简单请求:如果请求的方法是
GET
、POST
或HEAD
,并且请求头只包含以下几种:Accept
Accept-Language
Content-Language
Content-Type
(仅限于application/x-www-form-urlencoded
、multipart/form-data
或text/plain
)
浏览器不会发送预检请求(Preflight Request),直接发起跨域请求。
-
复杂请求:如果请求的方法不是
GET
、POST
或HEAD
,或者请求头包含了其他非标准的头信息,浏览器会在实际请求之前发送一个OPTIONS
请求,称为预检请求。服务器需要先响应这个预检请求,确认是否允许跨域请求。 -
凭证请求:如果请求中带有凭证(如Cookies、HTTP认证信息等),浏览器会要求服务器在响应中明确允许凭证的跨域传输。
CORS响应头
服务器可以通过在响应中添加以下头信息来控制跨域行为:
Access-Control-Allow-Origin
:指定允许访问的源(可以是一个具体的域名,也可以是*
表示允许所有来源)。Access-Control-Allow-Methods
:指定允许的HTTP方法(如GET
、POST
等)。Access-Control-Allow-Headers
:指定允许的请求头。Access-Control-Allow-Credentials
:指定是否允许发送凭证(如Cookies)。Access-Control-Max-Age
:指定预检请求的结果可以缓存的时间(以秒为单位)。
@CrossOrigin注解
@CrossOrigin
是Spring提供的一种简单的方式来启用CORS支持。你可以直接在控制器类或方法上使用这个注解,来为特定的API接口开启跨域支持。
基本用法
@RestController
@RequestMapping("/api")
public class MyController {
@CrossOrigin
@GetMapping("/data")
public ResponseEntity<String> getData() {
return ResponseEntity.ok("Hello, World!");
}
}
在这个例子中,/api/data
这个API接口将允许来自任何来源的跨域请求。如果你只想允许特定的来源,可以在注解中指定origins
参数:
@CrossOrigin(origins = "http://example.com")
@GetMapping("/data")
public ResponseEntity<String> getData() {
return ResponseEntity.ok("Hello, World!");
}
参数详解
@CrossOrigin
注解支持多个参数,帮助你更灵活地控制跨域行为:
参数 | 类型 | 描述 |
---|---|---|
origins |
String[] | 允许的来源列表,可以是具体的域名,也可以是* 表示允许所有来源 |
methods |
RequestMethod[] | 允许的HTTP方法,默认是所有方法 |
allowedHeaders |
String[] | 允许的请求头,默认是所有头 |
exposedHeaders |
String[] | 暴露给浏览器的响应头 |
allowCredentials |
boolean | 是否允许发送凭证,默认是false |
maxAge |
long | 预检请求的结果可以缓存的时间(以秒为单位),默认是1800秒 |
示例:完整的@CrossOrigin
配置
@CrossOrigin(
origins = "http://example.com",
methods = {RequestMethod.GET, RequestMethod.POST},
allowedHeaders = {"Content-Type", "Authorization"},
exposedHeaders = {"X-Total-Count"},
allowCredentials = "true",
maxAge = 3600
)
@GetMapping("/data")
public ResponseEntity<String> getData() {
return ResponseEntity.ok("Hello, World!");
}
优点与局限
- 优点:
@CrossOrigin
注解非常简洁,适合小型项目或只需要为个别API接口开启跨域支持的场景。 - 局限:如果整个应用都需要跨域支持,或者你需要更复杂的CORS配置,
@CrossOrigin
可能显得不够灵活。这时,我们可以考虑使用CorsFilter
。
CorsFilter过滤器
CorsFilter
是Spring提供的另一种方式来全局配置CORS。它可以通过配置文件或Java代码的方式,为整个应用程序统一设置跨域规则。相比@CrossOrigin
注解,CorsFilter
更加灵活,适合大型项目或需要全局跨域配置的场景。
通过配置文件启用CorsFilter
你可以在application.properties
或application.yml
中配置CORS:
spring:
mvc:
cors:
enabled: true
mappings:
[/api/**]:
allowed-origins: "http://example.com"
allowed-methods: "GET, POST, PUT, DELETE"
allowed-headers: "Content-Type, Authorization"
exposed-headers: "X-Total-Count"
allow-credentials: true
max-age: 3600
通过Java代码启用CorsFilter
你也可以通过Java代码来配置CorsFilter
。下面是一个示例:
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class CorsConfig {
@Bean
public CorsFilter corsFilter() {
// 创建CorsConfiguration对象
CorsConfiguration corsConfig = new CorsConfiguration();
corsConfig.setAllowCredentials(true);
corsConfig.addAllowedOrigin("http://example.com");
corsConfig.addAllowedHeader("*");
corsConfig.addAllowedMethod("*");
// 创建UrlBasedCorsConfigurationSource对象
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/api/**", corsConfig);
// 返回CorsFilter
return new CorsFilter(source);
}
}
更复杂的配置
CorsFilter
还支持更复杂的配置,例如为不同的路径设置不同的CORS规则:
@Configuration
public class CorsConfig {
@Bean
public CorsFilter corsFilter() {
CorsConfiguration corsConfig1 = new CorsConfiguration();
corsConfig1.setAllowCredentials(true);
corsConfig1.addAllowedOrigin("http://example.com");
corsConfig1.addAllowedHeader("*");
corsConfig1.addAllowedMethod("*");
CorsConfiguration corsConfig2 = new CorsConfiguration();
corsConfig2.setAllowCredentials(false);
corsConfig2.addAllowedOrigin("http://another-example.com");
corsConfig2.addAllowedHeader("Authorization");
corsConfig2.addAllowedMethod("GET");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/api/**", corsConfig1);
source.registerCorsConfiguration("/admin/**", corsConfig2);
return new CorsFilter(source);
}
}
优点与局限
- 优点:
CorsFilter
提供了全局配置的能力,适合大型项目或需要统一管理跨域规则的场景。它还可以为不同的路径设置不同的CORS规则,灵活性更高。 - 局限:相比
@CrossOrigin
注解,CorsFilter
的配置稍微复杂一些,尤其是在小型项目中,可能会显得过于繁琐。
总结
今天我们一起探讨了Spring中的两种CORS配置方式:@CrossOrigin
注解和CorsFilter
过滤器。@CrossOrigin
注解简单易用,适合小型项目或个别API接口的跨域配置;而CorsFilter
则提供了更强大的全局配置能力,适合大型项目或需要统一管理跨域规则的场景。
无论你选择哪种方式,关键是要根据项目的实际需求来决定。希望今天的分享能帮助你更好地理解和应用CORS配置,让你的前后端分离项目更加顺畅地运行!
最后,别忘了在实际开发中多参考官方文档,尤其是Spring的官方文档,里面有很多详细的说明和最佳实践。祝大家 coding 快乐!