SpringCloud系列之閘道器(Gateway)應用篇

吳碼發表於2020-04-19

@

前言

由於專案採用了微服務架構,業務功能都在相應各自的模組中,每個業務模組都是以獨立的專案執行著,對外提供各自的服務介面,如沒有類似閘道器之類元件的話,相應的鑑權,限流等功能實現起來不能夠進行統一的配置和管理,有了閘道器後一切都是如此的優雅。剛好新專案中採用了SpringCloud Gateway元件作為閘道器,就記錄下專案中常用的配置吧。

專案版本

spring-boot-version:2.2.5.RELEASE
spring-cloud.version:Hoxton.SR3

閘道器訪問

示例專案還是延續SpringCloud系列原先的示例程式碼,引入閘道器僅僅只需新增spring-cloud-gateway專案即可。
核心pom.xml(詳細資訊檢視示例原始碼,在文章末尾)

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

bootstrap.yml

server:
  port: 9005
spring:
  application:
    name: springcloud-gateway-service
  cloud:
    config:
      discovery:
        enabled: true
        service-id: config-server
      profile: dev
      label: master
    gateway:
      enabled: true  #開啟閘道器
      discovery:
        locator:
          enabled: true #開啟自動路由,以服務id建立路由,服務id預設大寫
          lower-case-service-id: true #服務id設定為小寫
eureka:
  client:
    service-url:
      defaultZone: http://localhost:9003/eureka/

ApiGatewayApplication.java

@EnableDiscoveryClient
@SpringBootApplication
public class ApiGatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(ApiGatewayApplication.class, args);
    }
}

訪問原先spring-cloud-system-server模組對外提供的介面
http://localhost:9004/web/system/getEnvName

通過閘道器進行訪問
http://localhost:9005/system-server/web/system/getEnvName

請求能正常返回,那就說明閘道器元件已整合進來了,是不是很簡單呢,一行配置項就搞定了,便於展現這邊採用properties配置方式說明

spring.cloud.gateway.discovery.locator.enabled=true

到此閘道器的基礎配置應用已完成,通過閘道器訪問的請求路徑格式如下
http://閘道器地址:閘道器埠/各自服務id/各自服務對外提供的URL訪問

鑑權配置

這邊將spring-cloud-system-server模組引入spring security安全認證元件,上程式碼。
pom.xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

application.properties

spring.security.user.name=test
spring.security.user.password=123456

服務模組調整完後,重新啟動該模組,訪問對外請求介面,出現認證登入介面說明配置成功。
http://localhost:9004/web/system/getEnvName

輸入上述配置項中配置的使用者名稱和密碼後,介面請求返回正常。

請求閘道器地址,訪問服務介面按下Enter鍵時會跳轉至服務專案認證頁面,如下
http://localhost:9005/system-server/web/system/getEnvName

接下來對閘道器模組進行相應調整
bootstrap.yml

spring:
  application:
    name: springcloud-gateway-service
  security:
    user:
      name: test
      password: 123456

新增安全認證過濾類
SecurityBasicAuthorizationFilter.java

@Component
public class SecurityBasicAuthorizationFilter implements GlobalFilter, Ordered {

    @Value("${spring.security.user.name}")
    private String username;
    @Value("${spring.security.user.password}")
    private String password;

    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String auth = username.concat(":").concat(password);
        String encodedAuth = new sun.misc.BASE64Encoder().encode(auth.getBytes(Charset.forName("US-ASCII")));
        String authHeader = "Basic " +encodedAuth;
        //headers中增加授權資訊
        ServerHttpRequest serverHttpRequest = exchange.getRequest().mutate().header("Authorization", authHeader).build();
        ServerWebExchange build = exchange.mutate().request(serverHttpRequest).build();
        return chain.filter(build);
    }
    /**
     * 優先順序
     * 數字越大優先順序越低
     * @return
     */
    public int getOrder() {
        return -1;
    }
}

重啟閘道器專案,重新訪問服務地址,返回正常資料。這邊說明下在測試時最好新開一個無痕視窗或者清理瀏覽器快取後再進行測試,不然因會話快取會導致安全認證沒有生效的假象。
http://localhost:9005/system-server/web/system/getEnvName
在這裡插入圖片描述

限流配置

SpringCloud Gateway自帶限流功能,但是基於redis,這邊簡單演示下,專案中沒有使用而是使用了阿里開源的sentinel,後續將介紹下整合sentinel元件。
pom.xml

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

bootstrap.yml

spring:
  cloud:
    gateway:
      enabled: true  #開啟閘道器
      discovery:
        locator:
          enabled: true #開啟自動路由,以服務id建立路由,服務id預設大寫
          lower-case-service-id: true #服務id設定為小寫
      routes:
        - id: baidu_route
          uri: https://www.baidu.com/
          predicates:
          - Path=/baidu/**
          filters:
            - name: RequestRateLimiter
              args:
                key-resolver: "#{@apiKeyResolver}"
                redis-rate-limiter.replenishRate: 1 #允許每秒處理多少個請求
                redis-rate-limiter.burstCapacity: 5 #允許在一秒鐘內完成的最大請求數
   redis:
    host: 192.168.28.142
    pool: 6379
    password: password
    database: 1              

RequestRateLimiterConfig.java

@Configuration
public class RequestRateLimiterConfig {
    @Bean
    @Primary
    public KeyResolver apiKeyResolver() {
        //URL限流,超出限流返回429狀態
        return exchange -> Mono.just(exchange.getRequest().getPath().toString());
    }
}

重新啟動閘道器專案,訪問如下請求地址,會請求跳轉至百度首頁,目前配置項配置為1s內請求數5次,超過5次就會觸發限流,返回429狀態碼,多次重新整理就會出現如下頁面
http://localhost:9005/baidu/test

通過monitor命令實時檢視redis資訊

本次閘道器專案目錄結構

同系列文章
1-SpringCloud系列之配置中心(Config)使用說明
2-SpringCloud系列之服務註冊發現(Eureka)應用篇
示例原始碼

相關文章