# SpringBoot怎么解决跨域 ## 一、什么是跨域问题 ### 1.1 跨域的定义 跨域(Cross-Origin)是指浏览器出于安全考虑,限制网页脚本向不同源(协议+域名+端口)的服务发起HTTP请求。这是浏览器的同源策略(Same-Origin Policy)导致的限制。 ### 1.2 同源策略详解 同源策略要求以下三个必须相同: - 协议(http/https) - 域名(www.example.com) - 端口(80/443) 示例对比: | 当前URL | 请求URL | 是否同源 | 原因 | |---------|---------|---------|------| | http://a.com | http://a.com/api | 是 | 仅路径不同 | | https://a.com | http://a.com | 否 | 协议不同 | | http://a.com:8080 | http://a.com | 否 | 端口不同 | ### 1.3 跨域的常见场景 1. 前后端分离开发时,前端域名与API服务域名不同 2. 调用第三方API服务 3. 微服务架构中服务间调用 ## 二、SpringBoot解决跨域的5种方案 ### 2.1 使用@CrossOrigin注解 #### 2.1.1 方法级配置 ```java @RestController @RequestMapping("/api") public class MyController { @CrossOrigin @GetMapping("/users") public List<User> getUsers() { // ... } }
@CrossOrigin(origins = "http://localhost:3000", maxAge = 3600, allowedHeaders = {"Content-Type","Authorization"}) @RestController @RequestMapping("/api") public class MyController { // 所有方法都支持跨域 }
参数 | 说明 | 示例值 |
---|---|---|
origins | 允许的源 | “http://a.com” |
methods | 允许的HTTP方法 | {RequestMethod.GET, RequestMethod.POST} |
allowedHeaders | 允许的请求头 | {“Content-Type”,“X-Token”} |
exposedHeaders | 暴露的响应头 | {“X-Custom-Header”} |
maxAge | 预检请求缓存时间(秒) | 1800 |
@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("*") .allowedMethods("GET", "POST", "PUT", "DELETE") .allowedHeaders("*") .allowCredentials(true) .maxAge(3600); } }
@Bean public CorsFilter corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); config.addAllowedOrigin("http://localhost:3000"); config.addAllowedHeader("*"); config.addAllowedMethod("*"); config.setMaxAge(3600L); source.registerCorsConfiguration("/**", config); return new CorsFilter(source); }
server { listen 80; server_name api.example.com; location / { proxy_pass http://localhost:8080; # CORS headers add_header 'Access-Control-Allow-Origin' '$http_origin' always; add_header 'Access-Control-Allow-Credentials' 'true' always; add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always; add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization' always; # 处理OPTIONS预检请求 if ($request_method = 'OPTIONS') { return 204; } } }
@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.cors().and() .authorizeRequests() // 其他安全配置... .anyRequest().authenticated(); } @Bean CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000")); configuration.setAllowedMethods(Arrays.asList("GET","POST")); configuration.setAllowCredentials(true); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", configuration); return source; } }
@Component public class SimpleCORSFilter implements Filter { public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletResponse response = (HttpServletResponse) res; response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE"); response.setHeader("Access-Control-Max-Age", "3600"); response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization"); chain.doFilter(req, res); } // 其他Filter方法... }
当请求满足以下条件时,浏览器会先发送OPTIONS预检请求: 1. 使用PUT、DELETE等非简单方法 2. 设置了自定义请求头 3. Content-Type不是以下三种: - text/plain - multipart/form-data - application/x-www-form-urlencoded
响应头 | 说明 | 示例值 |
---|---|---|
Access-Control-Allow-Origin | 允许的源 | * 或 http://a.com |
Access-Control-Allow-Methods | 允许的方法 | GET, POST, OPTIONS |
Access-Control-Allow-Headers | 允许的请求头 | Content-Type, X-Token |
Access-Control-Expose-Headers | 暴露的响应头 | X-Custom-Header |
Access-Control-Max-Age | 预检请求缓存时间 | 86400 |
Access-Control-Allow-Credentials | 是否允许发送cookie | true |
当需要发送cookie或认证信息时: 1. 前端需要设置withCredentials: true
2. 服务端必须: - 指定具体域名(不能是*) - 设置Access-Control-Allow-Credentials: true
axios.get('http://api.example.com/data', { withCredentials: true });
方案 | 适用场景 | 优点 | 缺点 |
---|---|---|---|
@CrossOrigin | 简单项目/特定接口 | 配置简单 | 不适合复杂配置 |
全局CORS配置 | 大多数SpringBoot项目 | 统一管理 | 需要理解配置项 |
Nginx代理 | 生产环境部署 | 性能好,统一入口 | 需要运维知识 |
Spring Security | 已使用Security的项目 | 与认证集成 | 配置较复杂 |
自定义Filter | 需要高度定制 | 完全控制流程 | 需要手动处理细节 |
allowedOrigins("*")
:应该明确指定允许的域名allowedMethods("*")
SpringBoot提供了多种灵活的跨域解决方案,开发者可以根据项目需求选择合适的方式。理解CORS的工作原理和浏览器行为对于正确配置至关重要。在安全性和便利性之间需要做好平衡,特别是在生产环境中要谨慎配置。
随着前端技术的发展,跨域问题会持续存在,但通过合理的架构设计(如API网关、微服务聚合层)可以减少前端直接面对跨域问题的机会。掌握这些解决方案将帮助开发者构建更健壮的Web应用系统。 “`
这篇文章共计约3900字,包含了: 1. 跨域问题的原理说明 2. 5种解决方案及代码示例 3. 技术细节和最佳实践 4. 方案对比和选型建议 5. 常见问题排查方法
格式采用标准的Markdown语法,包含代码块、表格、列表等元素,可以直接用于技术文档发布。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。