Spring Cloud配置跨域訪問的五種方案?你用的是哪一種呢?

在使用SpringCloud實現微服務時,經常會碰到前端頁面訪問多個二級域名的情況,跨域是首先要解決的問題。

解決這個問題,可以從兩方面入手,一種方案是在微服務各自的業務模塊中實現,即在SpringBoot層實現,另外一種方案就是在Gateway層實現。

首先講一下在SpringBoot層實現的三種方案。

解決方案一:在Controller上添加@CrossOrigin註解

這種方式適合只有一兩個rest接口需要跨域或者沒有網關的情況下,這種處理方式就非常簡單,適合在原來基代碼基礎上修改,影響比較小。

  @CrossOrigin // 註解方式 

  @RestController

   public class HandlerScanController {

        @CrossOrigin(allowCredentials="true", allowedHeaders="*", methods=      {RequestMethod.GET,

  RequestMethod.POST, RequestMethod.DELETE,                                        RequestMethod.OPTIONS,

  RequestMethod.HEAD,

  RequestMethod.PUT,

  RequestMethod.PATCH},

  origins="*")

     @PostMapping("/confirm")

     public Response handler(@RequestBody Request json){

        return null;

       }

  }

解決方案二:增加WebMvcConfigurer全局配置

如果有大量的rest接口的時候,顯然第一種方案已經不適合了,工作量大,也容易出錯,那就通過全局配置的方式,允許SpringBoot端所有的rest接口都支持跨域訪問,這個時候就需要考慮安全性的問題。

代碼如下:

@Configuration

public class MyConfiguration {

@Bean

 public WebMvcConfigurer corsConfigurer() {

     return new WebMvcConfigurerAdapter() {

         @Override

          public void addCorsMappings(CorsRegistry registry) {

              registry.addMapping("/**")

              .allowCredentials(true)

              .allowedMethods("GET");

           }

       };

     }

}

解決方案三:結合Filter使用

這種方案的使用場景跟第二種方案類似,只不過換成使用Filter的方式實現。
在spring boot的主類中,增加一個CorsFilter

 /**  

  * attention:簡單跨域就是GET,HEAD和POST請求,但是POST請求  的"Content-Type"只能是application/x-www-form-urlencoded, multipart/form-data 或 text/plain 

 * 反之,就是非簡單跨域,此跨域有一個預檢機制,說直白點,就是會發兩次請求,一次OPTIONS請求,一次真正的請求

  */

     @Bean

   public CorsFilter corsFilter() {

        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();

       final CorsConfiguration config = new CorsConfiguration();

        config.setAllowCredentials(true); // 允許cookies跨域

        config.addAllowedOrigin("*");// #允許向該服務器提交請求的URI,*表示全部允許,在SpringMVC中,如果設成*,會自動轉成當前請求頭中的Origin

        config.addAllowedHeader("*");// #允許訪問的頭信息,*表示全部

        config.setMaxAge(18000L);// 預檢請求的緩存時間(秒),即在這個時間段裏,對於相同的跨域請求不會再預檢了

        config.addAllowedMethod("OPTIONS");// 允許提交請求的方法,*表示全部允許

        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);

}

以上這種方案如果微服務多的話,需要在每個服務的主類上都加上這麼段代碼,增加了維護量。

以上三種方案都是在SpringBoot的基礎上實現的解決方案,在模塊較多或者接口較多的情況下不易維護。

既然SpringCloud自帶Gateway,下面就講講使用Gateway的跨域解決方案。

解決方案四,在Gateway端增加CorsFilter攔截器

這種方案跟方案三有些類似,只不過是放到了Gateway端,對於有多個微服務模塊的情況下,就大大減少了SpringBoot模塊端的代碼量,讓各個模塊更集中精力做業務邏輯實現。這個方案只需要在Gateway裏添加Filter代碼類即可。

public class CorsWebFilter implements WebFilter {

private static final String ALL = "*";

private static final String MAX_AGE = "18000L";

@Override

public Mono<Void> filter(ServerWebExchange ctx, WebFilterChain chain) {

    ServerHttpRequest request = ctx.getRequest();

    String path=request.getPath().value();

    ServerHttpResponse response = ctx.getResponse();

    if("/favicon.ico".equals(path)) {

        response.setStatusCode(HttpStatus.OK);

        return Mono.empty();

    }

    

    if (!CorsUtils.isCorsRequest(request)) {

        return chain.filter(ctx);

    }

    HttpHeaders requestHeaders = request.getHeaders();

    

    HttpMethod requestMethod = requestHeaders.getAccessControlRequestMethod();

    HttpHeaders headers = response.getHeaders();

    headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, requestHeaders.getOrigin());

    headers.addAll(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, requestHeaders.getAccessControlRequestHeaders());

    if (requestMethod != null) {

        headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, requestMethod.name());

    }

    headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");

    headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, ALL);

    headers.add(HttpHeaders.ACCESS_CONTROL_MAX_AGE, MAX_AGE);

    if (request.getMethod() == HttpMethod.OPTIONS) {

        response.setStatusCode(HttpStatus.OK);

        return Mono.empty();

    }

    

    

    return chain.filter(ctx);

}


}

解決方案五,修改Gateway配置文件

在仔細閱讀過Gateway的文檔你就會發現,原來CorsFilter早已經在Gateway裏了,不需要自己寫代碼實現,而且更靈活,修改配置文件即可,結合配置中心使用,可以實現動態修改。

application.yml.

spring:
cloud:

gateway:      
  globalcors:        
    corsConfigurations:
      '[/**]': 
        allowedOrigins: "docs.spring.io"  
        allowedMethods:
        - GET


以上五種跨域方案講完了,你用的哪一種呢?還是在自己寫代碼實現嗎?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章