Spring Boot 允許跨域設置失敗的問題深究


在公司開發過程中,一個前后端分離的項目遇見了跨域的問題。

前端控制台報錯:No 'Access-Control-Allow-Origin' header is present on the requested resource.

從經驗得知:spring boot解決跨域問題。兩種解決方法:

1、重寫 WebMvcConfigurer 類,並注入到spring容器中:

@Configuration
public class CustomCorsConfiguration implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**").allowedOrigins("*").allowedMethods("GET", "POST", "OPTIONS", "PUT")
                .allowedHeaders("Content-Type", "X-Requested-With", "accept", "Origin", "Access-Control-Request-Method",
                        "Access-Control-Request-Headers")
                .exposedHeaders("Access-Control-Allow-Origin", "Access-Control-Allow-Credentials")
                .allowCredentials(true).maxAge(3600);
    }
}

這個底層我猜想是一種攔截器,他的優先級在過濾器之后。也就是說執行完過濾器,才會執行這個攔截器。

2、在@Configuration中,注入CorsFilter:

    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", corsConfig());
        return new CorsFilter(source);
    }

    private CorsConfiguration corsConfig() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        // 請求常用的三種配置,*代表允許所有,也可以自定義屬性(比如 header 只能帶什么,只能是 post 方式等)
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        corsConfiguration.setAllowCredentials(true);
        corsConfiguration.setMaxAge(3600L);
        return corsConfiguration;
    }
        

這個底層就是過濾器,想要獲得服務器的跨域允許,必須經過此CorsFilter

 

不過,在嘗試了兩種方法發現,why?我的項目還是報錯:No 'Access-Control-Allow-Origin' header is present on the requested resource.

 

在使用第二種方法,並經過調試后發現了問題,CorsFilter 的執行順序在token過濾器的后面!

 

 

 這時候再來了解下跨域的原理,詳見 http://www.ruanyifeng.com/blog/2016/04/cors.html

我這邊前端是屬於跨域中的非簡單請求,他的過程是:在前端真正發送請求api接口的http時,會發出一個類似於嗅探的假請求給服務器,這個假請求會從服務器攜帶信息,告知頁面是否允許頁面跨域訪問,如果允許,則發出真正的http,如果不,瀏覽器控制台直接報錯。

我這個項目的問題就出在這。如果這個嗅探沒到達CorsFilter,就被服務器攔截下來了,那么他得到的信息肯定是 不允許跨域訪問 ! 我們的嗅探就是被項目中的jwt過濾器攔截下來了,因為我在項目中的設定是每個請求必須攜帶jwt的token,否則被攔截下來,而嗅探是一種瀏覽器生成的簡單請求,肯定不攜帶jwt token,因此被攔截下來了,也就沒法到達CorsFilter,就沒法獲得跨域的許可。所以在使用百度的第二種方法就失敗了!

 

那么第一種百度的方法失敗的原因呢?更簡單了!因為第一種底層是攔截器(WebMvcConfigurer),他的執行優先級在過濾器之后,所以嗅探的http在到這個攔截器的時候,早就被jwt過濾器擋下來了,因此提示跨域失敗!

 

聽了上述分析,是否解決思路已經有了呢?對,只要我們的嗅探http到達CorsFilter過濾器或者攔截器(WebMvcConfigurer)就行了,但是我們的jwt過濾必須得要,所以我的解決方法是,修改CorsFilter的優先級

    @Bean
    public FilterRegistrationBean corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", corsConfig());
        FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
        //*****這里設置了優先級*****
     bean.setOrder(1);
        return bean;
    }

    private CorsConfiguration corsConfig() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        // 請求常用的三種配置,*代表允許所有,也可以自定義屬性(比如 header 只能帶什么,只能是 post 方式等)
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        corsConfiguration.setAllowCredentials(true);
        corsConfiguration.setMaxAge(3600L);
        return corsConfiguration;
    }

 

 

完美解決!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM