天天看點

Spring Cloud Alibaba系列(四)gateway網關

什麼是網關

在微服務架構裡,服務的粒度被進一步細分,各個業務服務可以被獨立的設計、開發、測試、部署和管理。這時,各個獨立部署單元可以用不同的開發測試團隊維護,可以使用不同的程式設計語言和技術平台進行設計,這就要求必須使用一種語言和平台無關的服務協定作為各個單元間的通訊方式。

換句話說就是網關為所有的請求提供了統一的入口,友善我們對服務請求和響應做統一管理。

為什麼要用網關

API 網關是一個處于應用程式或服務(提供 REST API 接口服務)之前的系統,用來管理授權、通路控制和流量限制等,這樣 REST API 接口服務就被 API 網關保護起來,對所有的調用者透明。

什麼是gateway

Spring Cloud Gateway是Spring官方基于Spring 5.0,Spring Boot 2.0和Project Reactor等技術開發的網關,Spring Cloud Gateway旨在為微服務架構提供一種簡單而有效的統一的API路由管理方式。Spring Cloud Gateway作為Spring Cloud生态系中的網關,目标是替代ZUUL,其不僅提供統一的路由方式,并且基于Filter鍊的方式提供了網關基本的功能,例如:安全,監控/埋點,和限流等。

gateway工作原理

用戶端向Spring Cloud網關送出請求。如果網關處理程式映射确定請求與路由比對,則将其發送到網關Web處理程式。該處理程式運作通過特定于請求的過濾器鍊發送請求。過濾器由虛線分隔的原因是,過濾器可以在發送代理請求之前或之後執行邏輯。執行所有“前置”過濾器邏輯,然後發出代理請求。發出代理請求後,将執行“後”過濾器邏輯。

路由規則

路由和過濾器是gateway中非常重要的兩個概念,gateway本身提供了非常豐富的路由規則和多種過濾器來适配我們的需求。gateway提供了11種路由規則,分别是:

  • 後置路由謂詞工廠
    該謂詞比對在目前日期時間之後發生的請求。參數名為 After
               
  • 前置路由謂詞工廠
    該謂詞比對目前日期時間之前發生的請求。參數名為 Before
               
  • 時間段路由謂詞工廠
    該謂詞比對在datetime1之後和datetime2之前發生的請求。參數名為 Between
               
  • cookie路由謂詞工廠
    該謂詞比對具有給定名稱的cookie,并且值比對正規表達式。參數名為 Cookie
               
  • 标頭路由謂詞工廠
    該謂詞與具有給定名稱的标頭比對,并且值與正規表達式比對。參數名為 Header
               
  • 主機路由謂詞工廠
    該謂詞是指由路由進行比對,比對多個路由時用,隔開。參數名為 Host
               
  • 方法路由謂詞工廠
    該參數是一個或多個要比對的HTTP方法。參數名為 Method
               
  • 路徑路由謂詞工廠
    該謂詞是指在請求路徑上加一個字首,以此來比對。參數名為 Path
               
  • 查詢路由謂詞工廠
  • RemoteAddr路由謂詞工廠
  • 重量路線謂詞工廠

其中,我們比較常用的就是路徑路由謂詞工廠,配合StripPrefix GatewayFilter工廠,實作我們的路由比對轉發。

路徑路由謂詞工廠配置如下:

spring:
  cloud:
    gateway:
      discovery:
          locator:
              enabled: true # 開啟從注冊中心動态建立路由的功能,利用微服務名稱進行路由
      routes:
          # 路由id,建議配合服務名
        - id: demo_route 
          #比對路由名
          uri: lb://demo-provider 
          predicates:
          # 斷言,路徑相比對的進行路由
          - Path=/demo/**            

配置的含義就是,如果請求路徑中是/demo/**,則轉發到demo-provider服務。

網關過濾器

在spring cloud gateway 2.2.2.RELEASE版本中,已經預設實作了30種過濾器。

序号 過濾器工廠 作用 參數
1 AddRequestHeader 為原始請求添加Header Header的名稱及值
2 AddRequestParameter 為原始請求添加請求參數 參數名稱及值
3 AddResponseHeader 為原始響應添加Header
4 DedupeResponseHeader 剔除響應頭中重複的值 需要去重的Header名稱及去重政策
5 Hystrix 為路由引入Hystrix的斷路器保護 HystrixCommand的名稱
6 CircuitBreaker 為路由引入Resilience4J斷路器保護 CircuitBreaker的名稱
7 FallbackHeaders 為fallbackUri的請求頭中添加具體的異常資訊 Header的名稱
MapRequestHeader 更新原始請求中的Header Header的值
9 PrefixPath 為原始請求頭添加字首 字首路徑
10 PreserveHostHeader 為請求添加preserverHostHeader=true的屬性,路由過濾器會檢查該屬性以決定是否要發送原始的host
11 RequestRateLimiter 用于對請求限流,限流算法為令牌桶 keyResolver、rateLimiter、statusCode、denyEmptyKey、emptyKeyStatus
12 RedirectTo 将原始請求重定向到指定的url http狀态碼及重定向的url
13 RemoveHopByHopHeadersFilter 為原始請求删除IETF組織規定的一系列Header 預設就會啟用,可以通過配置指定僅删除哪些Header
14 RemoveRequestHeader 為原始請求删除某個Header Header名稱
15 RemoveResponseHeader 為原始響應删除某個Header
16 RewritePath 重寫原始的請求路徑 原始路徑正規表達式以及重寫後路徑的正規表達式
17 RewriteLocationResponseHeader 重寫響應頭的

Location

的值
18 RewriteResponseHeader 重寫原始響應中的某個Header Header名稱,值的正規表達式,重寫後的值
19 SaveSession 在轉發請求之前,強制執行

WebSession::save

操作
20 SecureHeaders 為原始響應添加一系列起安全作用的響應頭 無,支援修改這些安全響應頭的值
21 SetPath 修改原始的請求路徑 修改後的值
22 SetRequestHeader 修改原始請求中的某個Header的值 Header名稱,修改後的值
23 SetResponseHeader 修改原始響應中某個Header的值
24 SetStatus 修改原始響應的狀态碼 HTTP 狀态碼,可以是數字,也可以是字元串
25 StripPrefix 用于截斷原始請求的路徑 使用數字表示要截斷的路徑的數量
26 Retry 針對不同的響應進行重試 retries、statuses、methods、series
27 RequestSize 設定允許接收最大請求包的大小。如果請求包大小超過設定的值,則傳回

413 Payload Too Large

413 Payload Too Large

請求包大小,機關為位元組,預設值為5M
28 ModifyRequestBody 在轉發請求之前修改原始請求體内容 修改後的請求體内容
29 ModifyResponseBody 修改原始響應體的内容 修改後的響應體内容
30 Default 為所有路由添加過濾器 過濾器工廠名稱及值

這裡比較常用的如第25種,配置如下:

spring:
  cloud:
    gateway:
      discovery:
          locator:
              enabled: true # 開啟從注冊中心動态建立路由的功能,利用微服務名稱進行路由
      routes:
          # 路由id,建議配合服務名
        - id: demo_route 
          #比對路由名
          uri: lb://demo-provider 
          predicates:
          # 斷言,路徑相比對的進行路由
          - Path=/demo/** 
          filters:
          - StripPrefix=1           

一般情況下我們配合path路由使用,這裡的意思是假如,我們的demo-provider服務種有一個/test的接口,實際上我們的請求路徑經過網關時應該時/demo/test,這樣就能把這個路由分發到demo-provider服務中,但是分發過去的路由是/demo/test,和我們實際的/test接口不一樣。這時候我們用StripPrefix=1,來截取掉一級路由,這樣轉發過去的路由就是/test了。

自定義網關過濾器

除了上面提供的30種過濾器外,我們還可以實作自定義的過濾器。

1. 實作GatewayFilter接口和Ordered接口

gatewayFilter接口是為了實作請求過濾,ordered接口是為了給過濾器設定優先級,值越大級别越低。

想要實作一個自定義的過濾器,無非就是兩個步驟:1.實作過濾器,2.将過濾器添加到具體路由上。

public class TokenGatewayFilter implements GatewayFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        System.out.println("這裡處理自身邏輯");

        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

@Configuration
class RouteConfiguration{

    @Bean
    public RouteLocator routeLocator(RouteLocatorBuilder builder){

        return builder.routes().route( r->
                r.path("/demo/**")
                .uri("lb://demo-provider ")
                .filter(new TokenGatewayFilter())
                .id("demo_route "))
                .build();
    }
}           

2.繼承AbstractGatewayFilterFactory類

@Component
public class TokenCheckGatewayFilterFactory extends AbstractGatewayFilterFactory<TokenCheckGatewayFilterFactory.Config> {
    public TokenCheckGatewayFilterFactory() {
        super(Config.class);
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("enabled");
    }
    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            system.out.println("這裡處理自身邏輯")
            return chain.filter(exchange);
        };

    }

    public static class Config {
        // 控制是否開啟認證
        private boolean enabled = true;

        public Config() {}

        public boolean isEnabled() {
            return enabled;
        }

        public void setEnabled(boolean enabled) {
            this.enabled = enabled;
        }
    }
}           

這裡我們可以直接在application.yml中為需要過濾的路由添加這個過濾器。

spring:
  cloud:
    gateway:
      routes:
        - id: demo_route # 路由id,建議配合服務名
          uri: lb://demo-provider #比對路由名
          predicates:
          - Path=/demo/** # 斷言,路徑相比對的進行路由
          filters:
          - TokenCheck=true           

需要注意的是,這個地方自定義的過濾器名稱必須是XXGatewayFilterFactory,并且配置檔案中配置過濾器時名字必須時這個XX。

當然,我們也可以為每個路由都添加這個過濾器,可以直接這樣寫配置,而不用在每個路由上都去寫。

spring:
  cloud:
    gateway:
      default-filters:
        - TokenCheck=true           

3.實作GlobalFilter和ordered

這個GlobalFilter從名字中就可以看出,是一個全局過濾器,也就是說實作這個接口後,所有的請求都會被過濾,我們就不需要在去找往某個路由中加過濾器了。

@Component
public class TokenGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("這裡處理自身邏輯");
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 0;
    }
}           

以上就是實作自定義網關過濾器的三種方式了。實際開發中根據需求來實作合适的過濾器就可以了。