6種SpringBoot解決跨域請求的方法整理
一、跨域問題簡介
在Web開發(fā)中,瀏覽器的同源策略(Same-Origin Policy)是一項重要的安全機制,它限制了一個源(Origin)中加載的文檔或腳本如何與另一個源的資源進行交互。所謂同源,指的是協(xié)議、域名和端口號都相同。當前端應用試圖請求與自身不同源的后端API時,就會遇到跨域問題。
例如,當 http://frontend.com
的前端應用嘗試訪問 http://backend.com/api
的后端服務時,瀏覽器會阻止這種請求,并在控制臺報錯:
Access to XMLHttpRequest at 'http://backend.com/api' from origin 'http://frontend.com'
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
跨域資源共享(CORS,Cross-Origin Resource Sharing)是一種標準機制,允許服務器聲明哪些源可以訪問其資源。在SpringBoot應用中,有多種方式可以解決跨域問題,下面詳細介紹6種常見的解決方案。
二、方案一:基于@CrossOrigin注解的方法級別控制
這是最簡單直接的方式,通過在Controller類或特定方法上添加@CrossOrigin
注解來允許跨域請求。
實現(xiàn)方式
// 在方法級別允許跨域 @RestController @RequestMapping("/api") public class UserController { @CrossOrigin(origins = "http://example.com") @GetMapping("/users") public List<User> getUsers() { // 方法實現(xiàn) return userService.findAll(); } @GetMapping("/roles") public List<Role> getRoles() { // 此方法不允許跨域 return roleService.findAll(); } } // 在類級別允許跨域 @CrossOrigin(origins = {"http://example.com", "http://localhost:3000"}) @RestController @RequestMapping("/api/products") public class ProductController { @GetMapping public List<Product> getAllProducts() { // 方法實現(xiàn) return productService.findAll(); } @GetMapping("/{id}") public Product getProduct(@PathVariable Long id) { // 方法實現(xiàn) return productService.findById(id); } }
優(yōu)點
- 實現(xiàn)簡單直觀
- 可以精確控制到方法級別
- 可以針對不同的API設(shè)置不同的CORS規(guī)則
缺點
- 代碼重復,需要在多個地方添加注解
- 維護成本高,當CORS策略變更時,需要修改多處代碼
- 不適合大型項目中統(tǒng)一管理CORS策略
三、方案二:全局CORS配置(WebMvcConfigurer)
通過實現(xiàn)WebMvcConfigurer
接口并重寫addCorsMappings
方法,可以在全局范圍內(nèi)配置CORS規(guī)則。
實現(xiàn)方式
@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/api/**") .allowedOrigins("http://example.com", "http://localhost:3000") .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") .allowedHeaders("*") .allowCredentials(true) .maxAge(3600); // 1小時內(nèi)不需要再預檢(發(fā)OPTIONS請求) } }
優(yōu)點
- 可以方便集中管理所有API的CORS配置
- 配置靈活,可以針對不同的URL模式設(shè)置不同的規(guī)則
- 代碼簡潔,易于維護
缺點
- 在某些場景下可能需要與其他安全配置結(jié)合使用
四、方案三:使用CorsFilter
通過定義CorsFilter
作為一個Bean,可以在過濾器級別處理跨域請求,這種方式比WebMvcConfigurer
的優(yōu)先級更高。
實現(xiàn)方式
@Configuration public class CorsConfig { @Bean public CorsFilter corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration config = new CorsConfiguration(); // 允許的源 config.addAllowedOrigin("http://example.com"); config.addAllowedOrigin("http://localhost:3000"); // 允許的HTTP方法 config.addAllowedMethod("*"); // 允許的頭信息 config.addAllowedHeader("*"); // 允許攜帶認證信息(Cookie等) config.setAllowCredentials(true); // 預檢請求的有效期,單位為秒 config.setMaxAge(3600L); // 對所有URL應用這些配置 source.registerCorsConfiguration("/**", config); return new CorsFilter(source); } }
優(yōu)點
- 在過濾器級別處理,可以攔截所有請求
- 優(yōu)先級高于方案二
- 可以與其他過濾器組合使用
- 適合在不修改已有Controller的情況下添加CORS支持
缺點
- 無法精確到方法級別控制
- 對于復雜的規(guī)則可能不夠靈活
五、方案四:Spring Security中的CORS配置
如果項目使用了Spring Security,需要在Security配置中允許CORS,否則Security可能會攔截跨域請求。
實現(xiàn)方式
@Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .cors(Customizer.withDefaults()) // 使用CorsConfigurationSource的默認配置 .csrf().disable() .authorizeHttpRequests(authorize -> authorize .requestMatchers("/api/**").authenticated() .anyRequest().permitAll() ) .httpBasic(Customizer.withDefaults()); return http.build(); } @Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); configuration.setAllowedOrigins(Arrays.asList("http://example.com", "http://localhost:3000")); configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS")); configuration.setAllowedHeaders(Arrays.asList("Authorization", "Content-Type")); configuration.setAllowCredentials(true); configuration.setMaxAge(3600L); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", configuration); return source; } }
優(yōu)點
- 與Spring Security無縫集成
- 可以結(jié)合認證和授權(quán)規(guī)則一起配置
- 適合需要安全控制的REST API
缺點
- 依賴Spring Security
- 對于不需要安全控制的簡單應用可能略顯復雜
六、方案五:網(wǎng)關(guān)層面解決跨域(Spring Cloud Gateway)
在微服務架構(gòu)中,可以在API網(wǎng)關(guān)層統(tǒng)一處理跨域問題,這樣后端微服務就不需要各自配置CORS了。
實現(xiàn)方式
// Spring Cloud Gateway配置 @Configuration public class GatewayConfig { @Bean public RouteLocator customRouteLocator(RouteLocatorBuilder builder) { return builder.routes() .route("user_service_route", r -> r.path("/api/users/**") .uri("lb://user-service")) .route("product_service_route", r -> r.path("/api/products/**") .uri("lb://product-service")) .build(); } @Bean public WebFilter corsFilter() { return (ServerWebExchange ctx, WebFilterChain chain) -> { ServerHttpRequest request = ctx.getRequest(); if (CorsUtils.isCorsRequest(request)) { ServerHttpResponse response = ctx.getResponse(); HttpHeaders headers = response.getHeaders(); headers.add("Access-Control-Allow-Origin", "*"); headers.add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); headers.add("Access-Control-Allow-Headers", "Authorization, Content-Type"); headers.add("Access-Control-Allow-Credentials", "true"); headers.add("Access-Control-Max-Age", "3600"); if (request.getMethod() == HttpMethod.OPTIONS) { response.setStatusCode(HttpStatus.OK); return Mono.empty(); } } return chain.filter(ctx); }; } }
優(yōu)點
- 集中處理所有微服務的跨域問題
- 后端服務無需關(guān)心跨域配置
- 便于統(tǒng)一管理和維護
- 適合微服務架構(gòu)
缺點
- 依賴Spring Cloud Gateway
- 配置相對復雜
- 對于單體應用可能過于重量級
七、方案六:使用代理服務器
通過配置前端開發(fā)服務器代理 (開發(fā)環(huán)境) 或使用Nginx (生產(chǎn)環(huán)境) 等反向代理服務器,可以間接解決跨域問題。這種方式實際上是繞過了瀏覽器的同源策略,而不是直接在后端解決CORS。
前端開發(fā)服務器代理配置(以Vue CLI為例)
// vue.config.js module.exports = { devServer: { proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true, pathRewrite: { '^/api': '/api' } } } } }
Nginx反向代理配置
server { listen 80; server_name frontend.example.com; location / { root /usr/share/nginx/html; index index.html; try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://backend.example.com:8080/api/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }
優(yōu)點
- 完全繞過瀏覽器的同源策略限制
- 后端無需任何CORS配置
缺點
- 需要額外的代理配置
- 增加了系統(tǒng)復雜性
- 可能引入額外的網(wǎng)絡延遲
八、方案比較與選擇建議
方案 | 實現(xiàn)難度 | 靈活性 | 維護成本 | 適用場景 |
---|---|---|---|---|
@CrossOrigin注解 | 低 | 高 | 高 | 小型項目,特定API需要跨域 |
WebMvcConfigurer | 中 | 中 | 低 | 大多數(shù)Spring Boot應用 |
CorsFilter | 中 | 中 | 低 | 需要優(yōu)先級高的CORS處理 |
Spring Security | 高 | 高 | 中 | 有安全需求的應用 |
網(wǎng)關(guān)層面解決 | 高 | 高 | 低 | 微服務架構(gòu) |
代理服務器 | 中 | 高 | 中 | 生產(chǎn)環(huán)境,嚴格的安全要求 |
九、最佳實踐與注意事項
1. 安全考慮
- 不要盲目設(shè)置
Access-Control-Allow-Origin: *
,應該明確指定允許的源 - 謹慎處理帶有憑證的請求(如Cookie),確保只允許受信任的源
- 對于敏感操作,考慮使用CSRF令牌進行保護
2. 性能優(yōu)化
- 合理設(shè)置
Access-Control-Max-Age
以減少預檢請求 - 避免在每個請求中都解析和構(gòu)建CORS頭
- 在網(wǎng)關(guān)層處理CORS可以減輕后端服務的負擔
3. 開發(fā)與調(diào)試
- 在開發(fā)環(huán)境可以適當放寬CORS限制,但在生產(chǎn)環(huán)境一定要收緊
- 使用瀏覽器開發(fā)者工具的Network面板調(diào)試CORS問題
十、總結(jié)
跨域請求是前后端分離開發(fā)中不可避免的問題,Spring Boot提供了多種解決方案。從簡單的@CrossOrigin
注解到復雜的網(wǎng)關(guān)配置,我們可以根據(jù)項目規(guī)模和需求選擇合適的方案。在實際開發(fā)中,建議綜合考慮安全性、靈活性和維護成本,選擇最適合項目的CORS解決方案。
對于大多數(shù)Spring Boot應用,推薦使用全局CORS配置(WebMvcConfigurer)方案,它提供了良好的平衡性;而對于微服務架構(gòu),則推薦在網(wǎng)關(guān)層統(tǒng)一處理CORS問題,以減少后端服務的配置負擔。
無論選擇哪種方案,都應該遵循"最小權(quán)限原則" ,只允許必要的源訪問必要的資源,確保系統(tǒng)的安全性。
以上就是6種SpringBoot解決跨域請求的方法整理的詳細內(nèi)容,更多關(guān)于SpringBoot解決跨域請求的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java字符串相關(guān)類StringBuffer的用法詳解
java.lang包下的StringBuffer類,代表著可變的字符序列,可以用來對字符串內(nèi)容進行增刪改操作。本文將通過示例詳細說說它的用法,感興趣的可以跟隨小編一起學習一下2022-10-10高分面試從Hotspot源碼層面剖析java多態(tài)實現(xiàn)原理
這篇文章主要為大家介紹了在面試中從Hotspot源碼層面來剖析java多態(tài)的實現(xiàn)原理,這樣回答薪資隨你開,有需要的朋友可以借鑒參考下,希望大家多多加薪2022-01-01Maven添加Tomcat插件實現(xiàn)熱部署代碼實例
這篇文章主要介紹了Maven添加Tomcat插件實現(xiàn)熱部署代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-04-04