[Java實戰]Spring Boot 解決跨域問題(十四)
一、CORS 問題背景
-
什么是跨域問題?
當瀏覽器通過 JavaScript 發起跨域請求(不同協議、域名、端口)時,會觸發同源策略限制,導致請求被攔截。
示例場景:前端運行在http://localhost:3000
,后端 API 部署在http://localhost:8080
。 -
CORS 機制的作用
- CORS(Cross-Origin Resource Sharing)是一種基于 HTTP 頭的安全機制。
- 允許服務端聲明哪些外部域可以訪問資源,解決合法跨域請求的限制。
二、Spring Boot 的 4 種解決方案
1. 使用 @CrossOrigin
注解(Controller 級別)
適用場景:僅需為單個接口或控制器開啟跨域支持。
實現方式:
@RestController
@RequestMapping("/api")
public class UserController {@CrossOrigin(origins = "http://localhost:3000")@GetMapping("/users")public List<User> getUsers() {return userService.findAll();}
}
配置參數:
origins
:允許的源(支持通配符*
,但不推薦生產環境使用)methods
:允許的 HTTP 方法(如GET, POST
)allowedHeaders
:允許的請求頭(如Content-Type, Authorization
)maxAge
:預檢請求緩存時間(單位:秒)
2. 全局 CORS 配置(推薦)
適用場景:為整個應用統一配置跨域規則。
實現方式:
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**").allowedOrigins("http://localhost:3000").allowedMethods("GET", "POST", "PUT", "DELETE").allowedHeaders("*").allowCredentials(true).maxAge(3600);}
}
關鍵配置說明:
addMapping("/**")
:對所有接口生效allowCredentials(true)
:允許攜帶 Cookie(需與allowedOrigins
明確指定域名配合)
3. 結合 Spring Security 的 CORS 配置
適用場景:應用啟用了 Spring Security 鑒權,需確保 CORS 配置不被安全過濾器攔截。
實現方式:
@Configuration
@EnableWebSecurity
public class SecurityConfig {@Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {http.cors(cors -> cors.configurationSource(corsConfigurationSource())).csrf().disable().authorizeRequests(auth -> auth.anyRequest().authenticated());return http.build();}@BeanCorsConfigurationSource corsConfigurationSource() {CorsConfiguration config = new CorsConfiguration();config.setAllowedOrigins(Arrays.asList("http://localhost:3000"));config.setAllowedMethods(Arrays.asList("GET", "POST"));UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();source.registerCorsConfiguration("/**", config);return source;}
}
注意事項:
- 必須通過
cors.configurationSource()
顯式配置,而非僅依賴WebMvcConfigurer
。 - 確保 Spring Security 的過濾器鏈順序正確(CORS 處理需在認證之前)。
4. 網關層統一處理(Nginx/Spring Cloud Gateway)
適用場景:微服務架構中,在網關層統一管理跨域策略。
示例(Nginx 配置):
server {listen 80;server_name api.example.com;location / {# CORS 配置add_header 'Access-Control-Allow-Origin' 'http://localhost:3000';add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,Content-Type,Authorization';add_header 'Access-Control-Allow-Credentials' 'true';if ($request_method = 'OPTIONS') {add_header 'Access-Control-Max-Age' 1728000;add_header 'Content-Type' 'text/plain; charset=utf-8';add_header 'Content-Length' 0;return 204;}proxy_pass http://backend-service;}
}
三、最佳實踐與調試技巧
-
避免使用通配符
*
- 生產環境中明確指定
allowedOrigins
,如https://your-frontend-domain.com
。 - 通配符會導致
allowCredentials(true)
失效,且存在安全風險。
- 生產環境中明確指定
-
處理預檢請求(OPTIONS)
- 瀏覽器對復雜請求(如帶自定義頭的 POST)會先發送 OPTIONS 請求。
- 確保后端正確處理 OPTIONS 方法(可通過全局配置或網關層實現)。
-
調試工具推薦
- 瀏覽器開發者工具:查看 Console 和 Network 標簽中的 CORS 錯誤信息。
- Postman:驗證接口是否正常工作(繞過瀏覽器限制)。
- curl 命令:模擬跨域請求:
curl -H "Origin: http://localhost:3000" -H "Access-Control-Request-Method: GET" -X OPTIONS http://localhost:8080/api/users
四、常見問題排查
-
配置未生效的可能原因
- 未正確引入
WebMvcConfigurer
或 Spring Security 配置沖突。 - 全局配置與
@CrossOrigin
注解混用時優先級問題(注解會覆蓋全局配置)。 - 緩存問題:瀏覽器可能緩存了舊的 CORS 響應頭,需強制刷新(
Ctrl + F5
)。
- 未正確引入
-
Spring Security 導致 CORS 失效
- 檢查安全配置中是否遺漏
.cors()
調用。 - 確保
CorsConfigurationSource
Bean 被正確注冊。
- 檢查安全配置中是否遺漏
-
攜帶 Cookie 時的特殊要求
- 前端請求需設置
withCredentials: true
(Axios 示例):axios.get('http://localhost:8080/api/data', { withCredentials: true });
- 后端需配置
allowCredentials(true)
且allowedOrigins
不能為*
。
- 前端請求需設置
五、進階:CORS 與 CSRF 的協同配置
若同時啟用 CSRF 保護(如表單提交場景):
@Configuration
@EnableWebSecurity
public class SecurityConfig {@Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {http.cors().configurationSource(corsConfigurationSource()).and().csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()).and().authorizeRequests().anyRequest().authenticated();return http.build();}
}
關鍵點:
- 使用
CookieCsrfTokenRepository
將 CSRF Token 存儲在 Cookie 中。 - 前端需從 Cookie 讀取
XSRF-TOKEN
并添加到請求頭。
六、總結
通過合理選擇注解配置、全局策略或網關層處理,Spring Boot 可以靈活解決各種跨域場景。關鍵點在于:
- 明確需求:區分開發環境與生產環境的配置嚴格性。
- 安全優先:避免過度開放權限,嚴格限制
allowedOrigins
。 - 全鏈路驗證:結合瀏覽器工具和后端日志進行調試。
附錄:官方文檔參考
- Spring CORS Documentation
- MDN CORS Guide
希望本教程對您有幫助,請點贊??收藏?關注支持!歡迎在評論區留言交流技術細節!