Spring Cloud入門-Gateway服務網關(Hoxton版本)

項目使用的Spring Cloud爲Hoxton版本,Spring Boot爲2.2.2.RELEASE版本

Spring Cloud入門系列彙總

序號 內容 鏈接地址
1 Spring Cloud入門-十分鐘瞭解Spring Cloud https://blog.csdn.net/ThinkWon/article/details/103715146
2 Spring Cloud入門-Eureka服務註冊與發現(Hoxton版本) https://blog.csdn.net/ThinkWon/article/details/103726655
3 Spring Cloud入門-Ribbon服務消費者(Hoxton版本) https://blog.csdn.net/ThinkWon/article/details/103729080
4 Spring Cloud入門-Hystrix斷路器(Hoxton版本) https://blog.csdn.net/ThinkWon/article/details/103732497
5 Spring Cloud入門-Hystrix Dashboard與Turbine斷路器監控(Hoxton版本) https://blog.csdn.net/ThinkWon/article/details/103734664
6 Spring Cloud入門-OpenFeign服務消費者(Hoxton版本) https://blog.csdn.net/ThinkWon/article/details/103735751
7 Spring Cloud入門-Zuul服務網關(Hoxton版本) https://blog.csdn.net/ThinkWon/article/details/103738851
8 Spring Cloud入門-Config分佈式配置中心(Hoxton版本) https://blog.csdn.net/ThinkWon/article/details/103739628
9 Spring Cloud入門-Bus消息總線(Hoxton版本) https://blog.csdn.net/ThinkWon/article/details/103753372
10 Spring Cloud入門-Sleuth服務鏈路跟蹤(Hoxton版本) https://blog.csdn.net/ThinkWon/article/details/103753896
11 Spring Cloud入門-Consul服務註冊發現與配置中心(Hoxton版本) https://blog.csdn.net/ThinkWon/article/details/103756139
12 Spring Cloud入門-Gateway服務網關(Hoxton版本) https://blog.csdn.net/ThinkWon/article/details/103757927
13 Spring Cloud入門-Admin服務監控中心(Hoxton版本) https://blog.csdn.net/ThinkWon/article/details/103758697
14 Spring Cloud入門-Oauth2授權的使用(Hoxton版本) https://blog.csdn.net/ThinkWon/article/details/103761687
15 Spring Cloud入門-Oauth2授權之JWT集成(Hoxton版本) https://blog.csdn.net/ThinkWon/article/details/103763364
16 Spring Cloud入門-Oauth2授權之基於JWT完成單點登錄(Hoxton版本) https://blog.csdn.net/ThinkWon/article/details/103766368
17 Spring Cloud入門-Nacos實現註冊和配置中心(Hoxton版本) https://blog.csdn.net/ThinkWon/article/details/103769680
18 Spring Cloud入門-Sentinel實現服務限流、熔斷與降級(Hoxton版本) https://blog.csdn.net/ThinkWon/article/details/103770879
19 Spring Cloud入門-Seata處理分佈式事務問題(Hoxton版本) https://blog.csdn.net/ThinkWon/article/details/103786102
20 Spring Cloud入門-彙總篇(Hoxton版本) https://blog.csdn.net/ThinkWon/article/details/103786588

摘要

Spring Cloud Gateway 爲 SpringBoot 應用提供了API網關支持,具有強大的智能路由與過濾器功能,本文將對其用法進行詳細介紹。

Gateway 簡介

Gateway是在Spring生態系統之上構建的API網關服務,基於Spring 5,Spring Boot 2和 Project Reactor等技術。Gateway旨在提供一種簡單而有效的方式來對API進行路由,以及提供一些強大的過濾器功能, 例如:熔斷、限流、重試等。

Spring Cloud Gateway 具有如下特性:

  • 基於Spring Framework 5, Project Reactor 和 Spring Boot 2.0 進行構建;
  • 動態路由:能夠匹配任何請求屬性;
  • 可以對路由指定 Predicate(斷言)和 Filter(過濾器);
  • 集成Hystrix的斷路器功能;
  • 集成 Spring Cloud 服務發現功能;
  • 易於編寫的 Predicate(斷言)和 Filter(過濾器);
  • 請求限流功能;
  • 支持路徑重寫。

相關概念

  • Route(路由):路由是構建網關的基本模塊,它由ID,目標URI,一系列的斷言和過濾器組成,如果斷言爲true則匹配該路由;
  • Predicate(斷言):指的是Java 8 的 Function Predicate。 輸入類型是Spring框架中的ServerWebExchange。 這使開發人員可以匹配HTTP請求中的所有內容,例如請求頭或請求參數。如果請求與斷言相匹配,則進行路由;
  • Filter(過濾器):指的是Spring框架中GatewayFilter的實例,使用過濾器,可以在請求被路由前後對請求進行修改。

創建 api-gateway模塊

這裏我們創建一個api-gateway模塊來演示Gateway的常用功能。

在pom.xml中添加相關依賴

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

兩種不同的配置路由方式

Gateway 提供了兩種不同的方式用於配置路由,一種是通過yml文件來配置,另一種是通過Java Bean來配置,下面我們分別介紹下。

使用yml配置

在application.yml中進行配置:

server:
  port: 9201

service-url:
  user-service: http://localhost:8201

spring:
  cloud:
    gateway:
      routes:
          # 路由的ID
        - id: path_route
          # 匹配後路由地址
          uri: ${service-url.user-service}/user/{id}
          predicates:
              # 斷言,路徑相匹配的進行路由
            - Path=/user/{id}

啓動eureka-server、user-service和api-gateway服務,並調用該地址測試:http://localhost:9201/user/1

我們發現該請求被路由到了user-service的該路徑上:http://localhost:8201/user/1

在這裏插入圖片描述

使用Java Bean配置

添加相關配置類,並配置一個RouteLocator對象:

@Configuration
public class GatewayConfig {

    @Bean
    public RouteLocator customerRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                .route("path_route2", r -> r.path("/user/getByUsername")
                        .uri("http://localhost:8201/user/getByUsername"))
                .build();
    }

}

重新啓動api-gateway服務,並調用該地址測試:http://localhost:9201/user/getByUsername?username=jourwon

我們發現該請求被路由到了user-service的該路徑上:http://localhost:8201/user/getByUsername?username=jourwon

在這裏插入圖片描述

Route Predicate 的使用

Spring Cloud Gateway將路由匹配作爲Spring WebFlux HandlerMapping基礎架構的一部分。 Spring Cloud Gateway包括許多內置的Route Predicate工廠。 所有這些Predicate都與HTTP請求的不同屬性匹配。 多個Route Predicate工廠可以進行組合,下面我們來介紹下一些常用的Route Predicate。

注意:Predicate中提到的配置都在application-predicate.yml文件中進行修改,並用該配置啓動api-gateway服務。

After Route Predicate

在指定時間之後的請求會匹配該路由。

spring:
  cloud:
    gateway:
      routes:
        - id: after_route
          uri: ${service-url.user-service}
          predicates:
            - After=2019-12-29T18:30:00+08:00[Asia/Shanghai]

Before Route Predicate

在指定時間之前的請求會匹配該路由。

spring:
  cloud:
    gateway:
      routes:
        - id: before_route
          uri: ${service-url.user-service}
          predicates:
            - Before=2019-12-29T18:30:00+08:00[Asia/Shanghai]

Between Route Predicate

在指定時間區間內的請求會匹配該路由。

spring:
  cloud:
    gateway:
      routes:
        - id: before_route
          uri: ${service-url.user-service}
          predicates:
            - Between=2019-12-29T18:30:00+08:00[Asia/Shanghai], 2019-12-30T18:30:00+08:00[Asia/Shanghai]

Cookie Route Predicate

帶有指定Cookie的請求會匹配該路由。

spring:
  cloud:
    gateway:
      routes:
        - id: cookie_route
          uri: ${service-url.user-service}
          predicates:
            - Cookie=username,jourwon

使用curl工具發送帶有cookie爲username=jourwon的請求可以匹配該路由。

curl http://localhost:9201/user/1 --cookie "username=jourwon"

Header Route Predicate

帶有指定請求頭的請求會匹配該路由。

spring:
  cloud:
    gateway:
      routes:
      - id: header_route
        uri: ${service-url.user-service}
        predicates:
        - Header=X-Request-Id, \d+

使用curl工具發送帶有請求頭爲X-Request-Id:123的請求可以匹配該路由。

curl http://localhost:9201/user/1 -H "X-Request-Id:123" 

Host Route Predicate

帶有指定Host的請求會匹配該路由。

spring:
  cloud:
    gateway:
      routes:
        - id: host_route
          uri: ${service-url.user-service}
          predicates:
            - Host=**.jourwon.com

使用curl工具發送帶有請求頭爲Host:www.jourwon.com的請求可以匹配該路由。

curl http://localhost:9201/user/1 -H "Host:www.jourwon.com" 

Method Route Predicate

發送指定方法的請求會匹配該路由。

spring:
  cloud:
    gateway:
      routes:
      - id: method_route
        uri: ${service-url.user-service}
        predicates:
        - Method=GET

使用curl工具發送GET請求可以匹配該路由。

curl http://localhost:9201/user/1

使用curl工具發送POST請求無法匹配該路由。

curl -X POST http://localhost:9201/user/1

Path Route Predicate

發送指定路徑的請求會匹配該路由。

spring:
  cloud:
    gateway:
      routes:
        - id: path_route
          uri: ${service-url.user-service}/user/{id}
          predicates:
            - Path=/user/{id}

使用curl工具發送/user/1路徑請求可以匹配該路由。

curl http://localhost:9201/user/1

使用curl工具發送/abc/1路徑請求無法匹配該路由。

curl http://localhost:9201/abc/1

Query Route Predicate

帶指定查詢參數的請求可以匹配該路由。

spring:
  cloud:
    gateway:
      routes:
      - id: query_route
        uri: ${service-url.user-service}/user/getByUsername
        predicates:
        - Query=username

使用curl工具發送帶username=jourwon查詢參數的請求可以匹配該路由。

curl http://localhost:9201/user/getByUsername?username=jourwon

使用curl工具發送帶不帶查詢參數的請求無法匹配該路由。

curl http://localhost:9201/user/getByUsername

RemoteAddr Route Predicate

從指定遠程地址發起的請求可以匹配該路由。

spring:
  cloud:
    gateway:
      routes:
      - id: remoteaddr_route
        uri: ${service-url.user-service}
        predicates:
        - RemoteAddr=192.168.1.1/24

使用curl工具從192.168.1.1發起請求可以匹配該路由。

curl http://localhost:9201/user/1

Weight Route Predicate

使用權重來路由相應請求,以下表示有80%的請求會被路由到localhost:8201,20%會被路由到localhost:8202。

spring:
  cloud:
    gateway:
      routes:
      - id: weight_high
        uri: http://localhost:8201
        predicates:
        - Weight=group1, 8
      - id: weight_low
        uri: http://localhost:8202
        predicates:
        - Weight=group1, 2

Route Filter 的使用

路由過濾器可用於修改進入的HTTP請求和返回的HTTP響應,路由過濾器只能指定路由進行使用。Spring Cloud Gateway 內置了多種路由過濾器,他們都由GatewayFilter的工廠類來產生,下面我們介紹下常用路由過濾器的用法。

AddRequestParameter GatewayFilter

給請求添加參數的過濾器。

spring:
  cloud:
    gateway:
      routes:
        - id: add_request_parameter_route
          uri: http://localhost:8201
          filters:
            - AddRequestParameter=username, jourwon
          predicates:
            - Method=GET

以上配置會對GET請求添加username=jourwon的請求參數,通過curl工具使用以下命令進行測試。

curl http://localhost:9201/user/getByUsername

相當於發起該請求:

curl http://localhost:8201/user/getByUsername?username=jourwon

StripPrefix GatewayFilter

對指定數量的路徑前綴進行去除的過濾器。

spring:
  cloud:
    gateway:
      routes:
      - id: strip_prefix_route
        uri: http://localhost:8201
        predicates:
        - Path=/user-service/**
        filters:
        - StripPrefix=2

以上配置會把以/user-service/開頭的請求的路徑去除兩位,通過curl工具使用以下命令進行測試。

curl http://localhost:9201/user-service/a/user/1

相當於發起該請求:

curl http://localhost:8201/user/1

PrefixPath GatewayFilter

與StripPrefix過濾器恰好相反,會對原有路徑進行增加操作的過濾器。

spring:
  cloud:
    gateway:
      routes:
      - id: prefix_path_route
        uri: http://localhost:8201
        predicates:
        - Method=GET
        filters:
        - PrefixPath=/user

以上配置會對所有GET請求添加/user路徑前綴,通過curl工具使用以下命令進行測試。

curl http://localhost:9201/1

相當於發起該請求:

curl http://localhost:8201/user/1

Hystrix GatewayFilter

Hystrix 過濾器允許你將斷路器功能添加到網關路由中,使你的服務免受級聯故障的影響,並提供服務降級處理。

要開啓斷路器功能,我們需要在pom.xml中添加Hystrix的相關依賴:

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

然後添加相關服務降級的處理類:

@RestController
public class FallbackController {

    @GetMapping("/fallback")
    public Object fallback() {
        Map<String,Object> result = new HashMap<>();
        result.put("data",null);
        result.put("message","Get request fallback!");
        result.put("code",500);
        return result;
    }


}

在application-filter.yml中添加相關配置,當路由出錯時會轉發到服務降級處理的控制器上:

spring:
  cloud:
    gateway:
      routes:
        - id: hystrix_route
          uri: ${service-url.user-service}
          predicates:
            - Method=GET
          filters:
            - name: Hystrix
              args:
                name: fallbackcmd
                fallback-uri: forward:/fallback

關閉user-service,調用該地址進行測試:http://localhost:9201/user/1 ,發現已經返回了服務降級的處理信息。

在這裏插入圖片描述

RequestRateLimiter GatewayFilter

RequestRateLimiter 過濾器可以用於限流,使用RateLimiter實現來確定是否允許當前請求繼續進行,如果請求太大默認會返回HTTP 429-太多請求狀態。

在pom.xml中添加相關依賴:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>

添加限流策略的配置類,這裏有兩種策略一種是根據請求參數中的username進行限流,另一種是根據訪問IP進行限流;

@Configuration
public class RedisRateLimiterConfig {

    @Bean
    public KeyResolver userKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("username"));
    }


    @Bean
    public KeyResolver ipKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
    }


}

我們使用Redis來進行限流,所以需要添加Redis和RequestRateLimiter的配置,這裏對所有的GET請求都進行了按IP來限流的操作;

spring:
  redis:
    host: localhost
    password: 123456
    port: 6379
  cloud:
    gateway:
      routes:
        - id: requestratelimiter_route
          uri: http://localhost:8201
          filters:
            - name: RequestRateLimiter
              args:
                # 每秒允許處理的請求數量
                redis-rate-limiter.replenishRate: 1
                # 每秒最大處理的請求數量
                redis-rate-limiter.burstCapacity: 2
                # 限流策略,對應策略的Bean
                key-resolver: "#{@ipKeyResolver}"
          predicates:
            - Method=GET

logging:
  level:
    org.springframework.cloud.gateway: debug

多次請求該地址:http://localhost:9201/user/1 ,會返回狀態碼爲429的錯誤;

在這裏插入圖片描述

Retry GatewayFilter

對路由請求進行重試的過濾器,可以根據路由請求返回的HTTP狀態碼來確定是否進行重試。

修改配置文件:

spring:
  cloud:
    gateway:
      routes:
      - id: retry_route
        uri: http://localhost:8201
        predicates:
        - Method=GET
        filters:
        - name: Retry
          args:
            retries: 1 #需要進行重試的次數
            statuses: BAD_GATEWAY #返回哪個狀態碼需要進行重試,返回狀態碼爲5XX進行重試
            backoff:
              firstBackoff: 10ms
              maxBackoff: 50ms
              factor: 2
              basedOnPreviousValue: false

當調用返回500時會進行重試,訪問測試地址:http://localhost:9201/user/111

可以發現user-service控制檯報錯2次,說明進行了一次重試。

2019-12-29 19:09:30.003 ERROR [user-service,,,] 2316 --- [nio-8201-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause

java.lang.NullPointerException: null

結合註冊中心使用

我們上次講到Spring Cloud入門-Zuul服務網關(Hoxton版本)結合註冊中心進行使用時,默認情況下Zuul會根據註冊中心註冊的服務列表,以服務名爲路徑創建動態路由,Gateway同樣也實現了該功能。下面我們演示下Gateway結合註冊中心如何使用默認的動態路由和過濾器。

使用動態路由

在pom.xml中添加相關依賴:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

添加application-eureka.yml配置文件:

server:
  port: 9201
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      discovery:
        locator:
          #開啓從註冊中心動態創建路由的功能
          enabled: true 
          #使用小寫服務名,默認是大寫
          lower-case-service-id: true 
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8001/eureka/
logging:
  level:
    org.springframework.cloud.gateway: debug

使用application-eureka.yml配置文件啓動api-gateway服務,訪問http://localhost:9201/user-service/user/1,可以路由到user-service的http://localhost:8201/user/1處。

使用過濾器

在結合註冊中心使用過濾器的時候,我們需要注意的是uri的協議爲lb,這樣才能啓用Gateway的負載均衡功能。

修改application-eureka.yml文件,使用了PrefixPath過濾器,會爲所有GET請求路徑添加/user路徑並路由;

server:
  port: 9201
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes:
        - id: prefixpath_route
          #此處需要使用lb協議
          uri: lb://user-service 
          predicates:
            - Method=GET
          filters:
            - PrefixPath=/user
      discovery:
        locator:
          enabled: true
eureka:
  client:
    service-url: 
      defaultZone: http://localhost:8001/eureka/
logging:
  level:
    org.springframework.cloud.gateway: debug

使用application-eureka.yml配置文件啓動api-gateway服務,訪問http://localhost:9201/1 ,可以路由到user-service的http://localhost:8201/user/1處。

使用到的模塊

springcloud-learning
├── eureka-server -- eureka註冊中心
├── user-service -- 提供User對象CRUD接口的服務
└── api-gateway -- gateway作爲網關的測試服務

項目源碼地址

GitHub項目源碼地址

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