Spring Cloud 前后端分離后引起的跨域訪問解決方案


背景

Spring Cloud 微服務試點改造,目前在嘗試前后端分離。

前台A應用(本機8080端口),通過網管(本機8769端口)調用后台應用B(本機8082端口)、應用C發布的http服務。。

A的js代碼如下:

$.ajax({
            type: "POST",
            async: "true",
            url: "http://127.0.0.1:8769/service-B/getResInfo",
            data:{resTypeId:201}
            dataType:"json",

xhrFields: {
                withCredentials: true
},
error: function (XMLHttpRequest, textStatus, errorThrown) { alert(textStatus + "," + errorThrown); }, beforeSend: function (XMLHttpRequest) { }, success: function (data) { ... } });

運行后報錯:

XMLHttpRequest cannot load http://127.0.0.1:8769/service-B/getResInfo. No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'http://localhost:8080' is therefore not allowed access.

問題原因

A的前台訪問B應用,導致了跨域。

跨域訪問違反了同源策略,同源策略規定:瀏覽器的ajax只能訪問跟它的前台頁面同源(相同域名或IP)的資源。

也就是說,如果A的前台訪問A的后台,則不會跨域。。

解決方案

嘗試了兩種解決辦法,最終采用了方案二。。

方案一:

在被調用的類或方法上增加@CrossOrigin注解來聲明自己支持跨域訪問

origins=*表示允許所有來源都支持,也可以定義特定的來源,比如http://domain1.com
allowCredentials=true 表示response里會增加標示Access-Control-Allow-Credentials=true
@RequestMapping(value="/getResInfo",method = {RequestMethod.POST})
@CrossOrigin(allowCredentials="true", allowedHeaders="*", methods={RequestMethod.POST}, origins="*")
    
public List<Map<String,Object>> getResInfo(@RequestParam(name = "resTypeId", required = false) String resTypeId){
。。。
}

如果只是針對某個服務需要被跨域訪問,用此方案可行。。

但由於我們進行了前后端分離,前台調用的都是跨域的服務,此方案需要對幾乎所有的B、C應用的服務對應的方法或者類上增加注解,不太合適。

而且,如果B、C服務都開放了跨域訪問,則可能存在安全隱患,因為其他未知應用也可以訪問這些服務。。

方案二:

在網管zuul里增加CorsFilter過濾器,比如下圖直接在啟動類里增加紅色部分代碼

@SpringBootApplication
@EnableZuulProxy
public class DemoZuulApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoZuulApplication.class, args);
    }
    
    @Bean public CorsFilter corsFilter() {
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        final CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true); // 允許cookies跨域
        config.addAllowedOrigin("*");// 允許向該服務器提交請求的URI,*表示全部允許。。這里盡量限制來源域,比如http://xxxx:8080 ,以降低安全風險。。
        config.addAllowedHeader("*");// 允許訪問的頭信息,*表示全部
        config.setMaxAge(18000L);// 預檢請求的緩存時間(秒),即在這個時間段里,對於相同的跨域請求不會再預檢了
        config.addAllowedMethod("*");// 允許提交請求的方法,*表示全部允許,也可以單獨設置GET、PUT等
    /*    config.addAllowedMethod("HEAD");
        config.addAllowedMethod("GET");// 允許Get的請求方法
        config.addAllowedMethod("PUT");
        config.addAllowedMethod("POST");
        config.addAllowedMethod("DELETE");
        config.addAllowedMethod("PATCH");*/
        source.registerCorsConfiguration("/**", config);
        return new CorsFilter(source); }

}

 

后來zuul上又增加了其他的過濾器,而此跨域過濾器必須在其他過濾器之前,所以寫法改成如下的方式,即借助FilterRegistrationBean將此過濾器的order設置為0,即最先加載的過濾器。。order值越大加載越晚。。

   @Bean
    public FilterRegistrationBean corsFilter() {

final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); final CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); // 允許cookies跨域 config.addAllowedOrigin("*");// #允許向該服務器提交請求的URI,*表示全部允許,在SpringMVC中,如果設成*,會自動轉成當前請求頭中的Origin config.addAllowedHeader("*");// #允許訪問的頭信息,*表示全部 config.setMaxAge(1800L);// 預檢請求的緩存時間(秒),即在這個時間段里,對於相同的跨域請求不會再預檢了 config.addAllowedMethod("*");// 允許提交請求的方法,*表示全部允許 /* config.addAllowedMethod("HEAD"); config.addAllowedMethod("GET");// 允許Get的請求方法 config.addAllowedMethod("PUT"); config.addAllowedMethod("POST"); config.addAllowedMethod("DELETE"); config.addAllowedMethod("PATCH");*/ source.registerCorsConfiguration("/**", config); FilterRegistrationBean bean = new FilterRegistrationBean(new org.springframework.web.filter.CorsFilter(source)); bean.setOrder(0); return bean; }

 

由於此方案是增加到網管上的,對B、C應用的代碼都無任何改造。。

且因為B、C未直接開放跨域訪問,所以其他應用無法跨越訪問B、C服務,比如A不經過網關直接訪問B、C應用會訪問失敗。。

后續會對網管應用裝配上SSO進行單點登錄校驗,來更好的保障服務安全。。

 

'Access-Control-Allow-Origin' header contains multiple values的報錯的解決方案

今天遇到一個跨域的報錯:f12谷歌瀏覽器發現

Failed to load http://127.0.0.1:8769/device-service/routeService/queryViewPathString: The 'Access-Control-Allow-Origin' header contains multiple values 'http://127.0.0.1:8080, http://127.0.0.1:8080', but only one is allowed. Origin 'http://127.0.0.1:8080' is therefore not allowed access.

這個問題是因為重復配置了跨域過濾器。。比如zuul里已經配置了CorsConfiguration,在業務應用里又配置了一次CorsConfiguration。。則會出現此問題。。

解決方案:去掉業務應用里的配置,統一在網關進行配置即可。

 

前端ajax跨域訪問后端時,如果需要cookie一並發送,則需要做增加withCredentials參數。。否則會引起后台獲取的session每次都變化的問題。


xhrFields: {
withCredentials: true
},
 

本文參考:http://blog.csdn.net/liuchuanhong1/article/details/62237705


免責聲明!

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



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