springboot的跨域是什么?遇到跨域问题如何解决?
在Spring Boot中,跨域是指当浏览器中的前端应用(如运行在某个域名和端口下的前端页面)请求后端接口时,如果后端接口所在的域名、端口或协议与前端应用不一致,浏览器会阻止这种跨域请求。这是由于浏览器的同源策略(Same-Origin Policy)所导致的。
跨域产生的原因:
浏览器出于安全性考虑,会阻止不同来源(域名、端口或协议不同)之间的请求
-
同源策略限制:浏览器出于安全考虑,实施了同源策略,即只允许页面请求同源(相同协议、域名和端口)的资源。当JavaScript发起的请求跨越了同源策略,即请求的目标与当前页面的域名、端口、协议不一致时,浏览器会阻止请求的发送或接收。
-
前后端分离架构:在现代的前后端分离开发模式下,前端和后端通常部署在不同的服务器上,具有不同的域名或端口,这很容易导致跨域问题。
例如:
- 前端运行在 http://localhost:3000
- 后端 API 在 http://localhost:8080
当前端向 http://localhost:8080/api/data 发送请求时,浏览器会拦截并报 CORS policy 错误。
解决跨域问题的常见方式:
方式 1:使用 @CrossOrigin 注解(推荐小型项目或单个接口)
在 Spring Boot 控制器(@RestController)上使用 @CrossOrigin 注解,允许跨域访问:
1) 允许所有来源访问整个控制器
@RestController @RequestMapping("/api") @CrossOrigin(origins = "*") // 允许所有来源 public class MyController { @GetMapping("/data") public String getData() { return "Hello, CORS!"; } }
2) 只允许特定的来源
@CrossOrigin(origins = "http://localhost:3000") // 只允许从 http://localhost:3000 访问 @GetMapping("/data") public String getData() { return "Hello, CORS!"; }
3) 细粒度控制(支持多个来源、方法、请求头)
@CrossOrigin(origins = {"http://localhost:3000", "http://example.com"}, methods = {RequestMethod.GET, RequestMethod.POST}, allowedHeaders = {"Content-Type", "Authorization"}) @GetMapping("/data") public String getData() { return "CORS Configured!"; }
方式 2:全局配置(推荐大型项目或所有接口都需要跨域)
如果所有 API 都需要支持跨域,使用 CorsFilter 或 WebMvcConfigurer 进行全局配置。
2.1) 使用 WebMvcConfigurer 配置全局 CORS,在 @Configuration 类中注册 CORS 规则:
-
在Spring Boot应用中,可以通过创建一个配置类,实现WebMvcConfigurer接口,并重写addCorsMappings方法来全局配置跨域访问。这种方式适用于所有接口都需要跨域访问的场景。
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class CorsConfig { @Bean public WebMvcConfigurer corsConfigurer() { return new WebMvcConfigurer() { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") // 允许所有路径 .allowedOrigins("http://localhost:3000") // 允许特定域访问 .allowedMethods("GET", "POST", "PUT", "DELETE") // 允许的请求方法 .allowedHeaders("*") // 允许所有请求头 .allowCredentials(true); // 允许携带 Cookie } }; } }
- addMapping("/**"):允许所有接口跨域
- allowedOrigins("http://localhost:3000"):只允许 http://localhost:3000 访问
- allowedMethods("GET", "POST", "PUT", "DELETE"):允许这些 HTTP 方法
- allowedHeaders("*"):允许所有请求头
- allowCredentials(true):允许携带 cookies 或 Authorization 头
2.2) 使用 CorsFilter 配置 CORS
另一种方式是使用 CorsFilter,这种方式也是通过Java配置的方式配置跨域访问,与全局配置CORS类似,但实现方式略有不同。
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; @Configuration public class MyCorsFilter { @Bean public CorsFilter corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration config = new CorsConfiguration(); config.setAllowedOrigins(Arrays.asList("http://localhost:3000")); // 允许的前端地址 config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE")); config.setAllowedHeaders(Arrays.asList("*")); config.setAllowCredentials(true); // 允许 Cookie source.registerCorsConfiguration("/**", config); return new CorsFilter(source); } }
- setAllowedOrigins(Arrays.asList("http://localhost:3000")):指定允许的域
- setAllowCredentials(true):允许带 Cookies(必须与 allowedOrigins 不能设置为 "*")
方式3. 允许携带 Cookie
如果前端需要携带 cookie 或 Authorization 头,例如 fetch 或 Axios 发送请求时 credentials: 'include',你需要:
- 在后端 allowCredentials(true)
- 在前端请求时 credentials: 'include'
后端
registry.addMapping("/**") .allowedOrigins("http://localhost:3000") .allowedMethods("GET", "POST") .allowCredentials(true); // 允许携带 Cookie
前端(使用 Fetch)
fetch('http://localhost:8080/api/data', { method: 'GET', credentials: 'include' // 允许携带 Cookie }) .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error(error));
前端(使用 Axios)
(图片来源网络,侵删)axios.get('http://localhost:8080/api/data', { withCredentials: true }) .then(response => console.log(response.data)) .catch(error => console.error(error));
方式4. 通过Nginx配置CORS
如果项目中使用了Nginx作为反向代理服务器,也可以在Nginx中配置CORS来解决跨域问题。
server { ... location / { add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Headers' '*'; add_header 'Access-Control-Allow-Methods' '*'; if ($request_method = 'OPTIONS') { return 204; } } ... }
通过以上方法,可以在Spring Boot应用中有效地解决跨域问题,确保前后端之间的正常通信。
(图片来源网络,侵删)常见 CORS 错误及解决方法
错误信息 可能原因 解决方案 Access to fetch at 'http://localhost:8080' from origin 'http://localhost:3000' has been blocked by CORS policy 后端未配置 CORS 配置 @CrossOrigin 或 WebMvcConfigurer Response to preflight request doesn’t pass access control check OPTIONS 请求被拦截 在后端允许 OPTIONS 方法 Missing Allow-Control-Allow-Origin header CORS 头未返回 确保后端 allowedOrigins 设置正确 credentials mode is 'include' but Access-Control-Allow-Credentials is missing 需要携带 Cookie 但未允许 在后端 allowCredentials(true) 总结
方法 适用场景 配置方式 @CrossOrigin 适用于单个接口 在 @RestController 或方法级别使用 WebMvcConfigurer 适用于整个项目 CorsRegistry 配置 CorsFilter 高级定制 使用 CorsConfiguration 在 Spring Boot 项目中,推荐使用 WebMvcConfigurer 进行全局跨域配置,@CrossOrigin 适用于局部控制。
(图片来源网络,侵删)
-