SpringCloud Alibaba-4-網關


1. 什么是API網關

API網關:是一個服務器,是系統的唯一入口。同時也可以實現服務的路由、負載均衡、鑒權、限流、熔斷等功能。

API網關出現的原因是微服務架構的出現,不同的微服務一般會有不同的網絡地址,而外部客戶端可能需要調用多個服務的接口才能完成一個業務需求,如果讓客戶端直接與各個微服務通信,會有以下的問題:

客戶端請求多個微服務,各個服務ip不一樣,增加客戶端復雜度。
存在跨域,在一定場景下處理相對復雜。
認證復雜,每個服務都需要獨立認證。
與微服務耦合太強,微服務變更,客戶端需要變更



2. 使用API網關的好處

所有的外部請求都會先經過API 網關這一層。也就是說,API 的實現方面更多的考慮業務邏輯,而安全、性能、監控可以交由 API 網關來做,這樣既提高業務靈活性又不缺安全性。

  • 易於監控
  • 統一認證
  • 減少客戶端與微服務交互,解耦接口依賴




3. 常用網關

Nginx+lua

Zuul                              Zuul是一種提供動態路由、監視、彈性、安全性等功能的邊緣服務。Zuul是Netflix出品的一個基於JVM路由和服務端的負載均衡器。

SpringCoud Gateway                Spring Cloud GateWay是Spring Cloud的⼀個全新項⽬【SpringCloud公司開發的】,⽬標是取代Netflix Zuul。





3. gateWay入門使用

3.-1 基本概念

  • 斷言:用於進行條件判斷,只有斷言都返回真,才會真正的執行路由。

  • 路由:路由是構建網關的基本模塊,它由ID,目標URI,斷言Predicates集合,過濾器Filters集合組成,如果斷言為true,則匹配該路由。

  • 過濾器:可以在請求被路由前后修改請求和響應的內容。基於過濾器可以實現:安全,監控,限流等問題。

3.0 創建一個服務

ip配置為80端口,當訪問這個服務,就是訪問我們的getWay。

# 服務端口
server.port=80
# 服務名
spring.application.name=service-gateway

3.1 請求轉發的實現

導入依賴

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

添加配置文件

spring:
  application:
    name: springcloud-gateway
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848  # 當有了注冊中心時,網關也是一個服務,所以需要注冊到注冊中心去。

    gateway:
      discovery:
        locator:
          enabled: true     # 讓gateway從nacos中獲取服務信息        

      routes:               # routes 是路由,一個GateWay可以包含多個route
        - id: to-user                       # 路由的id,必須唯一。用於區別其他Route。
          uri: lb://springcloud-consumer    # 路由指向的目的地 uri。     lb 動態路由,因為有了注冊中心,uri就不是是寫,而是寫它的服務實例名,lb代表負載均衡。
          order: 1                          # 路由的優先級,數字越小代表路由的優先級越高。
          predicates:                       # predicates  是斷言,一個ateWay可以包含多個predicate
            - Path=/user/**                 # 斷言規則,用於進行條件判斷,只有斷言都返回真,才會真正的執行路由。
          #filters:                         # 過濾器,用於在請求的傳遞過程中,對請求和響應做一些手腳



路由介紹:
Route:主要由 路由id、目標uri、斷言集合和過濾器集合組成。

  1. 路由標識,要求唯一,名稱任意(默認值 uuid,一般不用,需要自定義)
  2. uri:請求最終被轉發到的目標地址
  3. order: 路由優先級,數字越小,優先級越高
  4. predicates:斷言數組,即判斷條件,如果返回值是boolean,則轉發請求到 uri 屬性指定的服務中
  5. filters:過濾器數組,在請求傳遞過程中,對請求做一些修改



斷言介紹:

Spring Cloud Gateway包括許多內置的路由斷言工廠。所有這些斷言都與HTTP請求的不同屬性匹配。您可以將多個路由斷言工廠與邏輯 and 語句結合使用。

Spring Cloud Gateway 中的斷言命名都是有規范的,格式:“xxx + RoutePredicateFactory”,比如權重斷言 WeightRoutePredicateFactory,那么配置時直接取前面的 “Weight”。

也可以自定義斷言工廠,用到的時候百度吧。




過濾器介紹:

過濾器按區域划分,可分為全局,局部兩種過濾器。

  • 局部GatewayFilter:會應用到單個路由上
  • 全局GlobalFilter:會應用到所有路由上

過濾器按作用點划分,可分為Pre(前置),Post(后置)兩種過濾器。

  • Pre:在請求轉發到后端微服務之前執行。
  • Post:在請求執行完成之后執行。

Spring Cloud Gateway 中的過濾器命名都是有規范的,格式: "xxx + “GatewayFilterFactory”,比如PrefixPathGatewayFilterFactory,那么配置時直接取前面的 “PrefixPath”。




在Spring Cloud Gateway中內置了很多局部Filter。



3.2 介紹用得比較多的內置局部過濾器——Path路徑過濾器


Path相關過濾器可以實現URL重寫,通過重寫URL可以實現隱藏真實路徑提高安全性。

Path相關過濾器采用路徑正則表達式參數和替換參數,使用Java正則表達式來靈活地重寫請求路徑。


Gateway過濾器-自定義局部過濾器
自定義(局部)網關過濾器:https://www.bilibili.com/video/BV1R7411774f?p=42&spm_id_from=pageDriver
因為Gateway提供了很多Gateway內置網關(局部)過濾器,所以一般很少使用Gateway自定義網關過濾器。




在Spring Cloud Gateway中內置了很多全局Filter。

全局:會應用到所有的路由上。通過全局過濾器可以實現對權限的統一校驗,安全性驗證等功能。

多個 GlobalFilter 可以通過 @Order 或者 getOrder() 方法指定執行順序,order值越小,執行的優先級越高。

Gateway過濾器-自定義全局過濾器:

常見需求:用戶需要登錄了才放行。

    1. 當客戶端第一次請求服務時,服務端對用戶進行信息認證(登錄)
    2. 認證通過,將用戶信息進行加密形成token,返回給客戶端,作為登錄憑證
    3. 以后每次請求,客戶端都攜帶認證的token
    4. 服務端對token進行解密,判斷是否有效
// 自定義類實現 GlobalFilter , Ordered 接口,加上@Component注解即可;
@Component
public class MyCustomerGlobalFilter implements GlobalFilter ,Ordered {

  // 參數1:是一個響應交互的契約。提供對HTTP請求和響應的訪問,並公開額外的服務器端處理相關屬性和特性,如請求屬性。
  // 參數2:用於承載請求相關的屬性和請求體,Spring Cloud Gateway中底層使用Netty處理網絡請求。
  @Override
  public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
      ServerHttpRequest request = exchange.getRequest();
      ServerHttpResponse response = exchange.getResponse();

      // 判斷token,並驗證賬號密碼
      String token = request.getQueryParams().getFirst("token"); // 獲取請求對象中參數名為 token 的值,獲取第一個參數的值。
      if (StringUtils.isBlank(token)) {

          System.out.println("鑒權失敗");
          exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);

          return response.setComplete();
      }

      if(token.equale("abc")){
          // 放行
          return chain.filter(exchange);
      }
  }

  // 該方法用於聲明該過濾器執行的優先級
  @Override
  public int getOrder() {   // 返回值越低,表示過濾器執行的優先級越高。
    return 0;
  }
}



4. 跨域問題的解決

方法一:配置類方式

@Configuration
public class CorsConfig {
    @Bean
    public CorsWebFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedMethod("*");
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
        source.registerCorsConfiguration("/**", config);

        return new CorsWebFilter(source);
    }
}

方法二:配置文件方式

spring:
  cloud:
    gateway:
      globalcors: # 全局的跨域處理
        add-to-simple-url-handler-mapping: true # 解決options請求被攔截問題
        corsConfigurations:
          '[/**]':
            allowedOrigins: # 允許哪些網站的跨域請求   # 需要 注意的是在springboot2.4之前的版本是使用allowed-origins: "*",在springboot2.4之后的版本是 allowed-origin-patterns: "*"。
              - "http://localhost:8090"
              - "http://www.leyou.com"
            allowedMethods: # 允許的跨域ajax的請求方式
              - "GET"
              - "POST"
              - "DELETE"
              - "PUT"
              - "OPTIONS"
            allowedHeaders: "*" # 允許在請求中攜帶的頭信息
            allowCredentials: true # 是否允許攜帶cookie
            maxAge: 360000 # 這次跨域檢測的有效期



5. Nacos+Spring Cloud Gateway動態路由配置

將網關的一系列配置寫到項目的配置文件中,一旦路由策略發生改變必須要重啟項目,這樣維護成本很高,特別是服務網關作為系統的中心點,一旦重啟出現問題,影響面將是十分巨大的。

因此,我們將網關的配置存放到配置中心中,這樣由配置中心統一管理,一旦路由發生改變,只需要在配置中心修改即可,降低風險且實時失效。

https://www.cnblogs.com/jian0110/p/12862569.html




6. 自定義全局異常處理器

來源:https://blog.csdn.net/a745233700/article/details/122917167
一旦路由的微服務下線或者失聯了,Spring Cloud Gateway直接返回了一個錯誤頁面,如下圖:

顯然這種異常信息不友好,前后端分離架構中必須定制返回的異常信息。傳統的Spring Boot 服務中都是使用 @ControllerAdvice 來包裝全局異常處理的,但是由於服務下線,請求並沒有到達。

因此必須在網關中也要定制一層全局異常處理,這樣才能更加友好的和客戶端交互。

pring Cloud Gateway提供了多種全局處理的方式,今天只介紹其中一種方式,實現還算比較優雅:

直接創建一個類 GlobalErrorExceptionHandler,實現 ErrorWebExceptionHandler,重寫其中的 handle 方法,代碼如下:

/**
 * 用於網關的全局異常處理
 * @Order(-1):優先級一定要比ResponseStatusExceptionHandler低
 */
@Slf4j
@Order(-1)
@Component
@RequiredArgsConstructor
public class GlobalErrorExceptionHandler implements ErrorWebExceptionHandler {
 
 private final ObjectMapper objectMapper;
 
 @SuppressWarnings({"rawtypes", "unchecked", "NullableProblems"})
 @Override
 public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
  ServerHttpResponse response = exchange.getResponse();
  if (response.isCommitted()) {
   return Mono.error(ex);
  }
 
  // JOSN格式返回
  response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
  if (ex instanceof ResponseStatusException) {
   response.setStatusCode(((ResponseStatusException) ex).getStatus());
  }
 
  return response.writeWith(Mono.fromSupplier(() -> {
   DataBufferFactory bufferFactory = response.bufferFactory();
   try {
    //todo 返回響應結果,根據業務需求,自己定制
    CommonResponse resultMsg = new CommonResponse("500",ex.getMessage(),null);
    return bufferFactory.wrap(objectMapper.writeValueAsBytes(resultMsg));
   }
   catch (JsonProcessingException e) {
    log.error("Error writing response", ex);
    return bufferFactory.wrap(new byte[0]);
   }
  }));
 }
}



6. gateway整合sentinel

https://www.bilibili.com/video/BV1pF41147Aa?p=60&vd_source=61b6fb4e547748656e36b17ee95125fb
https://blog.csdn.net/a745233700/article/details/122917160


免責聲明!

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



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