Gateway 和 Zuul 都是网关,Gateway 的推出就是为了替换 Zuul,Getaway 的底层通讯时 Netty,是基于 WebFlux 来做请求处理的,基于异步通讯,效率比 Zuul 高很多

依赖

  1. <dependency>
  2. <groupId>org.springframework.cloud</groupId>
  3. <artifactId>spring-cloud-starter-gateway</artifactId>
  4. </dependency>

断言(谓词)

spring:
  application:
    name: component-gateway
  cloud:
    gateway:
      enabled: true # 动态插拔
      discovery:
        locator:
          enabled: true
      routes:
        - id: user
          uri: http://127.0.0.1:5000
          predicates:
            - After=2020-08-08T22:27:47.000+08:00 # 表示这个时间之后的请求,可以访问
            - Cookie=login, username # 必须有 cookie 且 cookie 的值 为 login=username
            - Query=name # 必须有 name 属性
            - Query=age # 必须有 age 属性
            - Header=X-Request-Id, \d+ # 设置 Header 属性
        - id: order
          uri: lb:http://SERVER-ORDER # 使用微服务名称进行路由
          predicates:
            - Path=/order/** # 拦截请求地址

过滤器

是在满足断言条件之后准备路由之前进行的

内置过滤器

spring:
  cloud:
    gateway:
      routes:
      - id: add_request_header_route
        uri: https://example.org
        filters:
            - AddRequestHeader=X-Request-red, blue
          - AddRequestParameter=color, blue
          - AddResponseHeader=X-Response-Red, blue
          - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin

与 Hystrix 整合(实现熔断、降级)

  • 依赖

    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>
    
  • 配置 ```yaml spring: application: name: component-gateway cloud: gateway:

    enabled: true # 动态插拔
    discovery:
      locator:
        enabled: true
    routes:
      - id: order
        uri: lb:http://SERVER-ORDER # 使用微服务名称进行路由
        predicates:
          - Query=test, debug
          - Path=/order/** # 拦截请求地址
        filters:
          - name: Hystrix
            args:
              name: fallbackcmd
              fallbackUri: forward:/fallback # 指本机的 URL 地址
    

hystrix: command: fallbackcmd: execution: isolation: thread: timeoutInMilliseconds: 1000 # 服务访问超时时间


- **Fallback Controller**
```java
@RestController
@RequestMapping("/fallback")
public class FallbackController {

    @RequestMapping
    public Mono<R> fallback() {
        return Mono.just(R.error("服务降级了"));
    }

}
  • 首先 filter 里头配置了 name 为 Hystrix 的 filter,实际是对应 HystrixGatewayFilterFactory
  • 然后指定了 hystrix command 的名称,及 fallbackUri,注意 fallbackUri 要以 forward 开头
  • 最后通过 hystrix.command.fallbackcmd.execution.isolation.thread.timeoutInMilliseconds 指定该 command 的超时时间

服务限流

Spring Cloud Gateway 自带限流器,使用了 Redis 来实现的令牌桶算法进行限流

  • 依赖

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

    spring:
    application:
      name: component-gateway
    
    redis:
      host: 127.0.0.1
      port: 6379
      timeout: 5000
    
    cloud:
      gateway:
        enabled: true # 动态插拔
        discovery:
          locator:
            enabled: true
        routes:
          - id: order
            uri: lb:http://SERVER-ORDER # 使用微服务名称进行路由
            predicates:
              - Query=test, debug
              - Path=/order/** # 拦截请求地址
            filters:
              - name: RequestRateLimiter # 限流,利用 redis 实现令牌桶过滤器
                key-resolver: "#{@ipKeyResolver}" # 令牌,对应 AppConfig 的 bean 名称
                args:
                  redis-rate-limiter:
                    replenishRate: 1 # 每秒生成的令牌数
                    burstCapacity: 2 # 最大的令牌数
                    requestedTokens: 1 # 每次请求获取一个令牌
    
  • AppConfig 配置 ```java @Configuration public class AppConfig {

    // IP 限流 @Bean public KeyResolver ipKeyResolver() {

      return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
    

    }

    // // 用户限流,使用这种方式限流,请求路径中必须携带 userId 参数 // @Bean // public KeyResolver userKeyResolver() { // return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst(“userId”)); // }

    // // 接口限流,获取请求地址的uri作为限流key // @Bean // public KeyResolver apiKeyResolver() { // return exchange -> Mono.just(exchange.getRequest().getPath().value()); // }

} ``` 上述配置如果在一秒内有超过2个以上的请求,就会进行限流操作,网页会报 429 错误
image.png
同时,Redis 会产生 2个 key
image.png
当有这个两个 key 的时候,此时无法访问该服务,大概 1 秒所有,当令牌桶重新产生了令牌后,该 key 会自动删除,此时即可再次访问服务