欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot中處理跨域請(qǐng)求CORS的全面指南

 更新時(shí)間:2025年04月08日 09:01:31   作者:北辰alk  
跨域資源共享是一種安全機(jī)制,它允許Web應(yīng)用程序在一個(gè)域上的資源請(qǐng)求另一個(gè)域上的資源,下面就跟隨小編一起來深入了解下SpringBoot中處理跨域請(qǐng)求CORS的具體操作吧

一、CORS基礎(chǔ)概念

1.1 什么是跨域請(qǐng)求

跨域資源共享(Cross-Origin Resource Sharing, CORS)是一種安全機(jī)制,它允許Web應(yīng)用程序在一個(gè)域上的資源請(qǐng)求另一個(gè)域上的資源。瀏覽器出于安全考慮,會(huì)阻止不同源之間的AJAX請(qǐng)求,這是**同源策略(Same-Origin Policy)**的限制。

1.2 同源策略定義

兩個(gè)URL被認(rèn)為是同源的條件:

  • 協(xié)議相同(http/https)
  • 域名相同
  • 端口相同

例如:

  • http://example.com/app1 和 http://example.com/app2 → 同源
  • http://example.com 和 https://example.com → 不同源(協(xié)議不同)
  • http://example.com 和 http://api.example.com → 不同源(域名不同)
  • http://example.com 和 http://example.com:8080 → 不同源(端口不同)

二、Spring Boot處理CORS的5種方式

2.1 全局配置(推薦)

方式1:使用WebMvcConfigurer接口

@Configuration
public class CorsConfig implements WebMvcConfigurer {
    
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")  // 所有接口
                .allowedOrigins("*")  // 允許所有源
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")  // 允許方法
                .allowedHeaders("*")  // 允許所有頭
                .allowCredentials(true)  // 允許憑證
                .maxAge(3600);  // 預(yù)檢請(qǐng)求緩存時(shí)間
    }
}

方式2:使用Filter方式(適用于Servlet應(yīng)用)

@Bean
public CorsFilter corsFilter() {
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    CorsConfiguration config = new CorsConfiguration();
    
    config.setAllowCredentials(true);
    config.addAllowedOrigin("*");
    config.addAllowedHeader("*");
    config.addAllowedMethod("*");
    source.registerCorsConfiguration("/**", config);
    
    return new CorsFilter(source);
}

2.2 控制器方法級(jí)配置

方式3:使用@CrossOrigin注解

@RestController
@RequestMapping("/api")
public class UserController {
    
    // 單個(gè)方法配置
    @CrossOrigin(origins = "http://localhost:3000")
    @GetMapping("/users")
    public List<User> getUsers() {
        // ...
    }
    
    // 整個(gè)控制器配置
    @CrossOrigin(origins = "*", maxAge = 3600)
    @RestController
    @RequestMapping("/products")
    public class ProductController {
        // ...
    }
}

2.3 屬性文件配置(Spring Boot 2.4+)

方式4:application.yml配置

spring:
  mvc:
    cors:
      allowed-origins: "http://localhost:3000, https://example.com"
      allowed-methods: "GET, POST, PUT, DELETE"
      allowed-headers: "*"
      exposed-headers: "Authorization, Content-Disposition"
      allow-credentials: true
      max-age: 1800

等效的application.properties:

spring.mvc.cors.allowed-origins=http://localhost:3000, https://example.com
spring.mvc.cors.allowed-methods=GET, POST, PUT, DELETE
spring.mvc.cors.allowed-headers=*
spring.mvc.cors.exposed-headers=Authorization, Content-Disposition
spring.mvc.cors.allow-credentials=true
spring.mvc.cors.max-age=1800

2.4 響應(yīng)頭手動(dòng)設(shè)置

方式5:手動(dòng)添加響應(yīng)頭(靈活但繁瑣)

@RestController
public class ApiController {
    
    @GetMapping("/manual")
    public ResponseEntity<String> manualCors() {
        return ResponseEntity.ok()
                .header("Access-Control-Allow-Origin", "*")
                .header("Access-Control-Allow-Methods", "GET")
                .body("Manual CORS configured");
    }
}

三、CORS處理深度解析

3.1 預(yù)檢請(qǐng)求(Preflight Request)

對(duì)于"非簡(jiǎn)單請(qǐng)求",瀏覽器會(huì)先發(fā)送OPTIONS預(yù)檢請(qǐng)求:

簡(jiǎn)單請(qǐng)求條件:

1.使用GET、HEAD或POST方法

2.僅包含以下頭:

  • Accept
  • Accept-Language
  • Content-Language
  • Content-Type (僅限 application/x-www-form-urlencoded, multipart/form-data, text/plain)

非簡(jiǎn)單請(qǐng)求示例:

fetch('http://api.example.com/data', {
  method: 'PUT',
  headers: {
    'Content-Type': 'application/json',
    'X-Custom-Header': 'value'
  },
  body: JSON.stringify({key: 'value'})
});

Spring Boot會(huì)自動(dòng)處理OPTIONS請(qǐng)求,無需開發(fā)者額外編碼。

3.2 核心響應(yīng)頭說明

響應(yīng)頭說明
Access-Control-Allow-Origin允許訪問的源,*表示任何源
Access-Control-Allow-Methods允許的HTTP方法
Access-Control-Allow-Headers允許的請(qǐng)求頭
Access-Control-Expose-Headers允許瀏覽器訪問的響應(yīng)頭
Access-Control-Allow-Credentials是否允許發(fā)送Cookie和HTTP認(rèn)證信息
Access-Control-Max-Age預(yù)檢請(qǐng)求結(jié)果的緩存時(shí)間(秒)

3.3 常見問題解決方案

問題1:allowCredentials(true)與allowedOrigins("*")沖突

錯(cuò)誤:

When allowCredentials is true, allowedOrigins cannot contain the special value "*"

解決方案:

// 替換為具體域名
.allowedOrigins("http://localhost:3000", "https://example.com")

問題2:前端仍然報(bào)CORS錯(cuò)誤

檢查步驟:

  • 確保后端已正確配置
  • 檢查瀏覽器控制臺(tái)錯(cuò)誤詳情
  • 使用Postman等工具驗(yàn)證接口是否正常工作
  • 檢查是否有多個(gè)CORS配置相互覆蓋

問題3:自定義過濾器干擾CORS

解決方案:

確保CorsFilter在過濾器鏈中的優(yōu)先級(jí):

@Bean
public FilterRegistrationBean<CorsFilter> corsFilterRegistration() {
    FilterRegistrationBean<CorsFilter> registration = new FilterRegistrationBean<>();
    registration.setFilter(corsFilter());
    registration.setOrder(Ordered.HIGHEST_PRECEDENCE);  // 最高優(yōu)先級(jí)
    return registration;
}

四、安全最佳實(shí)踐

4.1 生產(chǎn)環(huán)境配置建議

@Configuration
public class ProdCorsConfig implements WebMvcConfigurer {
    
    @Value("${app.cors.allowed-origins}")
    private String[] allowedOrigins;
    
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
                .allowedOrigins(allowedOrigins)
                .allowedMethods("GET", "POST")
                .allowedHeaders("Content-Type", "Authorization")
                .exposeHeaders("X-Custom-Header")
                .allowCredentials(true)
                .maxAge(3600);
    }
}

4.2 結(jié)合Spring Security

當(dāng)使用Spring Security時(shí),需要確保CORS配置在安全過濾器之前:

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and()  // 啟用Spring Security的CORS支持
            .csrf().disable()
            .authorizeRequests()
            // 其他配置...
    }
    
    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("https://trusted.com"));
        configuration.setAllowedMethods(Arrays.asList("GET", "POST"));
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
}

4.3 監(jiān)控與日志

添加CORS請(qǐng)求日志:

@Bean
public FilterRegistrationBean<CorsFilter> corsFilter() {
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    // ...配置
    
    FilterRegistrationBean<CorsFilter> registration = new FilterRegistrationBean<>();
    registration.setFilter(new CorsFilter(source) {
        @Override
        protected void doFilterInternal(HttpServletRequest request, 
            HttpServletResponse response, FilterChain filterChain) 
            throws ServletException, IOException {
            
            log.info("CORS請(qǐng)求: {} {}", request.getMethod(), request.getRequestURI());
            super.doFilterInternal(request, response, filterChain);
        }
    });
    return registration;
}

五、測(cè)試與驗(yàn)證

5.1 測(cè)試類示例

@SpringBootTest
@AutoConfigureMockMvc
public class CorsTest {
    
    @Autowired
    private MockMvc mockMvc;
    
    @Test
    public void testCorsHeaders() throws Exception {
        mockMvc.perform(options("/api/users")
                .header("Access-Control-Request-Method", "GET")
                .header("Origin", "http://localhost:3000"))
                .andExpect(header().exists("Access-Control-Allow-Origin"))
                .andExpect(header().string("Access-Control-Allow-Methods", "GET"));
    }
    
    @Test
    public void testActualRequest() throws Exception {
        mockMvc.perform(get("/api/users")
                .header("Origin", "http://localhost:3000"))
                .andExpect(status().isOk())
                .andExpect(header().string("Access-Control-Allow-Origin", "http://localhost:3000"));
    }
}

5.2 使用CURL測(cè)試

檢查OPTIONS預(yù)檢請(qǐng)求:

curl -X OPTIONS http://localhost:8080/api/users \
-H "Origin: http://test.com" \
-H "Access-Control-Request-Method: GET" \
-I

檢查實(shí)際請(qǐng)求:

curl -X GET http://localhost:8080/api/users \
-H "Origin: http://test.com" \
-I

六、總結(jié)與推薦方案

6.1 配置方式對(duì)比

方式適用場(chǎng)景優(yōu)點(diǎn)缺點(diǎn)
全局WebMvcConfigurer大多數(shù)應(yīng)用集中管理,支持細(xì)粒度配置需要代碼變更
過濾器方式需要最高優(yōu)先級(jí)處理處理最早,避免被其他過濾器干擾配置稍復(fù)雜
@CrossOrigin注解特定接口需要特殊規(guī)則精準(zhǔn)控制分散在各處,維護(hù)成本高
屬性文件配置簡(jiǎn)單需求,配置驅(qū)動(dòng)無需代碼變更靈活性較低
手動(dòng)設(shè)置響應(yīng)頭需要?jiǎng)討B(tài)決定CORS頭最大靈活性代碼侵入性強(qiáng)

6.2 推薦方案

新項(xiàng)目:

  • 使用WebMvcConfigurer全局配置
  • 結(jié)合屬性文件動(dòng)態(tài)配置允許的源
  • 對(duì)特殊接口使用@CrossOrigin覆蓋全局設(shè)置

已有項(xiàng)目遷移:

  • 先添加全局配置
  • 逐步移除分散的注解配置
  • 最終統(tǒng)一到1-2種管理方式

Spring Cloud微服務(wù):

  • 在API Gateway統(tǒng)一處理CORS
  • 各微服務(wù)禁用CORS或僅允許網(wǎng)關(guān)源
  • 結(jié)合OAuth2等安全機(jī)制

6.3 終極建議

生產(chǎn)環(huán)境不要使用*作為允許源 - 明確列出可信域名

限制允許的方法和頭 - 按最小權(quán)限原則配置

合理設(shè)置maxAge - 平衡安全性和性能(建議1小時(shí))

與前端團(tuán)隊(duì)協(xié)作 - 確保雙方對(duì)CORS要求理解一致

監(jiān)控CORS錯(cuò)誤 - 及時(shí)發(fā)現(xiàn)配置問題或惡意請(qǐng)求

通過合理配置CORS,可以在保障安全性的同時(shí),為現(xiàn)代前后端分離架構(gòu)提供必要的跨域支持。Spring Boot提供了多種靈活的方式,開發(fā)者應(yīng)根據(jù)項(xiàng)目實(shí)際需求選擇最適合的方案。

到此這篇關(guān)于SpringBoot中處理跨域請(qǐng)求CORS的全面指南的文章就介紹到這了,更多相關(guān)SpringBoot跨域請(qǐng)求CORS內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • MyBatis關(guān)閉一級(jí)緩存的兩種方式(分注解和xml兩種方式)

    MyBatis關(guān)閉一級(jí)緩存的兩種方式(分注解和xml兩種方式)

    這篇文章主要介紹了MyBatis關(guān)閉一級(jí)緩存的兩種方式(分注解和xml兩種方式),mybatis默認(rèn)開啟一級(jí)緩存,執(zhí)行2次相同sql,但是第一次查詢sql結(jié)果會(huì)加工處理這個(gè)時(shí)候需要關(guān)閉一級(jí)緩存,本文給大家詳細(xì)講解需要的朋友可以參考下
    2022-11-11
  • Java對(duì)文件的隨機(jī)讀寫以及壓縮處理操作

    Java對(duì)文件的隨機(jī)讀寫以及壓縮處理操作

    這篇文章主要介紹了Java對(duì)文件的隨機(jī)讀寫以及壓縮處理操作,是Java入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2015-10-10
  • 詳解使用Spring AOP和自定義注解進(jìn)行參數(shù)檢查

    詳解使用Spring AOP和自定義注解進(jìn)行參數(shù)檢查

    本篇文章主要介紹了詳解使用Spring AOP和自定義注解進(jìn)行參數(shù)檢查,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-04-04
  • java實(shí)現(xiàn)LFU算法的示例代碼

    java實(shí)現(xiàn)LFU算法的示例代碼

    LFU(Least Frequently Used)算法根據(jù)數(shù)據(jù)的歷史訪問頻率來淘汰數(shù)據(jù),其核心思想是“如果數(shù)據(jù)過去被訪問多次,那么將來被訪問的頻率也更高”,本文為大家整理了Java實(shí)現(xiàn)LFU算法的示例代碼,需要的可以參考下
    2023-11-11
  • Spring事件監(jiān)聽機(jī)制使用和原理解析

    Spring事件監(jiān)聽機(jī)制使用和原理解析

    Spring的監(jiān)聽機(jī)制基于觀察者模式,就是就是我們所說的發(fā)布訂閱模式,這種模式可以在一定程度上實(shí)現(xiàn)代碼的解耦,本文將從原理上解析Spring事件監(jiān)聽機(jī)制,需要的朋友可以參考下
    2023-06-06
  • java通過注解翻譯字典的實(shí)現(xiàn)示例

    java通過注解翻譯字典的實(shí)現(xiàn)示例

    本文主要介紹了java通過注解翻譯字典的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-04-04
  • Spring事件監(jiān)聽器ApplicationListener源碼詳解

    Spring事件監(jiān)聽器ApplicationListener源碼詳解

    這篇文章主要介紹了Spring事件監(jiān)聽器ApplicationListener源碼詳解,ApplicationEvent以及Listener是Spring為我們提供的一個(gè)事件監(jiān)聽、訂閱的實(shí)現(xiàn),內(nèi)部實(shí)現(xiàn)原理是觀察者設(shè)計(jì)模式,需要的朋友可以參考下
    2023-05-05
  • 如何用Intellij idea2020打包jar的方法步驟

    如何用Intellij idea2020打包jar的方法步驟

    這篇文章主要介紹了如何用Intellij idea 2020打包jar的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04
  • springboot中application.yml多環(huán)境生效規(guī)則說明

    springboot中application.yml多環(huán)境生效規(guī)則說明

    這篇文章主要介紹了springboot中application.yml多環(huán)境生效規(guī)則說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • MyBatis源碼分析之日志logging詳解

    MyBatis源碼分析之日志logging詳解

    這篇文章主要給大家介紹了關(guān)于MyBatis源碼分析之日志logging的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03

最新評(píng)論