SpringBoot2.6.13+Java8跨域配置实践
作者:bug攻城狮
文章介绍了三种跨域配置方案,并对比了它们的优缺点,方案一和方案二适用于开发环境,方案三适用于生产环境,如果使用SpringSecurity,推荐使用方案二,如果需要携带凭证,将allowCredentials设置为true
方案一:基于WebMvcConfigurer的配置
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 全局跨域配置类
* <p>
* 说明:
* 1. 使用 @Configuration 注解,让 Spring 在启动时加载此配置
* 2. 实现 WebMvcConfigurer 接口,重写 addCorsMappings 方法
* 3. 适用于 Spring MVC 项目
* <p>
* 注意:
* - 如果项目中同时使用了 Spring Security,需要在 Security 配置中允许跨域
* - 生产环境请将 allowedOriginPatterns 替换为具体的域名,不要使用 "*"
*/
@Configuration
public class GlobalCorsConfig implements WebMvcConfigurer {
// 定义允许的方法常量
private static final String[] ALLOWED_METHODS = {
"GET", // 读取
"POST", // 创建
"PUT", // 完全更新
"PATCH", // 部分更新
"DELETE", // 删除
"OPTIONS" // CORS 预检请求(必须)
};
/**
* 配置跨域规则
*
* @param registry CORS 注册器,用于配置跨域规则
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
// 添加跨域映射规则
registry.addMapping("/**") // 匹配所有请求路径
// 允许的源(域名)配置
// 注意:当 allowCredentials 为 true 时,不能使用 "*"
// 开发环境可以使用通配符,生产环境请替换为具体域名
.allowedOriginPatterns("*")
// 允许的 HTTP 方法
.allowedMethods(ALLOWED_METHODS)
// 允许的请求头
// 如果前端需要携带自定义头,需要在这里添加,如 "X-Token"
.allowedHeaders("*")
// 是否允许携带凭证(如 Cookies、Authorization 头等)
// 注意:如果设置为 true,则 allowedOriginPatterns 不能为 "*"
.allowCredentials(false)
// 预检请求的缓存时间(单位:秒)
// 在这个时间内,同一请求的预检请求不再发送
.maxAge(3600)
// 暴露给前端的响应头
// 如果前端需要访问某些自定义响应头,需要在这里暴露
.exposedHeaders("Authorization", "X-Token");
}
}
方案二:基于CorsFilter的配置(更灵活)
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import java.util.Arrays;
/**
* 基于 CorsFilter 的跨域配置
* <p>
* 优点:
* 1. 优先级更高,会在 Spring Security 之前执行
* 2. 可以更灵活地配置,支持动态源
* 3. 适用于所有请求,包括静态资源
* <p>
* 适用场景:
* 1. 需要更细粒度的跨域控制
* 2. 项目同时使用了 Spring Security
* 3. 需要根据请求动态判断是否允许跨域
*/
@Configuration
public class CorsFilterConfig {
// 定义允许的方法常量
private static final String[] ALLOWED_METHODS = {
"GET", // 读取
"POST", // 创建
"PUT", // 完全更新
"PATCH", // 部分更新
"DELETE", // 删除
"OPTIONS" // CORS 预检请求(必须)
};
/**
* 创建 CorsFilter Bean
*
* @return CorsFilter 跨域过滤器
*/
@Bean
public CorsFilter corsFilter() {
// 创建 CORS 配置对象
CorsConfiguration config = new CorsConfiguration();
// 设置是否允许携带凭证
// 注意:如果设置为 true,则不能使用 addAllowedOrigin("*")
config.setAllowCredentials(false);
// 设置允许的源(域名)
// 开发环境可以使用 "*",生产环境请替换为具体域名
config.addAllowedOriginPattern("*");
// 设置允许的 HTTP 方法
config.setAllowedMethods(Arrays.asList(ALLOWED_METHODS));
// 设置允许的请求头
config.setAllowedHeaders(Arrays.asList(
"Origin", "Content-Type", "Accept", "Authorization",
"X-Requested-With", "X-Token", "Cache-Control"
));
// 设置暴露给前端的响应头
config.setExposedHeaders(Arrays.asList(
"Authorization", "X-Token", "Content-Disposition"
));
// 设置预检请求的缓存时间(单位:秒)
config.setMaxAge(3600L);
// 创建基于 URL 的 CORS 配置源
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
// 注册 CORS 配置,应用到所有路径
source.registerCorsConfiguration("/**", config);
// 创建并返回 CorsFilter
return new CorsFilter(source);
}
}
方案三:生产环境推荐配置(带环境区分)
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import java.util.Arrays;
import java.util.List;
/**
* 生产环境跨域配置(带环境区分)
* <p>
* 特点:
* 1. 通过配置文件区分开发和生产环境
* 2. 开发环境允许所有源,生产环境只允许指定域名
* 3. 支持多个允许的域名
*/
@Configuration
public class EnvironmentBasedCorsConfig {
// 定义允许的方法常量
private static final String[] ALLOWED_METHODS = {
"GET", // 读取
"POST", // 创建
"PUT", // 完全更新
"PATCH", // 部分更新
"DELETE", // 删除
"OPTIONS" // CORS 预检请求(必须)
};
/**
* 应用运行环境
* 在 application.yml 中配置:env: dev/prod
*/
@Value("${env:dev}")
private String environment;
/**
* 生产环境允许的域名列表
* 在 application.yml 中配置:cors.allowed-origins: https://domain1.com,https://domain2.com
*/
@Value("${cors.allowed-origins:}")
private List<String> allowedOrigins;
@Bean
public CorsFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
// 根据环境设置不同的配置
if ("prod".equalsIgnoreCase(environment)) {
// 生产环境配置
config.setAllowCredentials(true);
// 设置允许的具体域名
if (allowedOrigins != null && !allowedOrigins.isEmpty()) {
allowedOrigins.forEach(config::addAllowedOriginPattern);
} else {
// 如果没有配置,默认不允许任何跨域(安全考虑)
config.addAllowedOriginPattern(""); // 空字符串表示不允许
}
} else {
// 开发/测试环境配置
config.setAllowCredentials(false);
config.addAllowedOriginPattern("*");
}
// 公共配置
config.setAllowedMethods(Arrays.asList(ALLOWED_METHODS));
config.setAllowedHeaders(Arrays.asList(
"Origin", "Content-Type", "Accept", "Authorization",
"X-Requested-With", "X-Token", "Cache-Control"
));
config.setExposedHeaders(Arrays.asList("Authorization", "X-Token"));
config.setMaxAge(3600L);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
对应的application.yml配置
# 应用配置 spring: application: name: your-application-name # 跨域配置(用于方案三) env: dev # 环境:dev-开发,prod-生产 # 生产环境允许的域名(多个用逗号分隔) cors: allowed-origins: https://www.yourdomain.com, https://api.yourdomain.com, http://localhost:3000 # 开发时保留
编码规则说明
这里以HTTP方法的跨域规则为例说明,其他所有可使用通配符的配置都是如此:
// 不推荐:过于宽松
config.addAllowedMethod("*");
// 推荐:明确列出需要的 HTTP 方法
config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
| 对比项 | 通配符* | 具体方法列表 |
|---|---|---|
| 安全性 | 较低(允许所有方法) | 较高(最小权限原则) |
| 清晰度 | 不明确允许哪些方法 | 明确列出允许的方法 |
| 兼容性 | 浏览器都支持 | 浏览器都支持 |
| 维护性 | 简单但模糊 | 清晰易于维护 |
| 推荐度 | ⭐⭐☆☆☆ | ⭐⭐⭐⭐⭐ |
使用建议
- 开发环境:使用方案一或方案二,配置简单
- 生产环境:使用方案三,严格控制允许的域名
- 如果使用 Spring Security:推荐使用方案二(CorsFilter),因为它的执行顺序更靠前
如果需要携带凭证(如 Cookies):
- 将
allowCredentials设置为true - 将
allowedOriginPatterns("*")改为具体的域名列表
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
