你真的了解GateWay网关吗?

139 阅读4分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

Gateway旨在提供一种简单而有效的方式来对API进行路由,以及提供一些强大的过滤器功能,例如:熔断,限流,重试等

——概念

  • Spring Cloud Gateway 使用的Webflux中的reactor-netty响应式编程组件,底层使用了Netty通讯框架,异步非阻塞。
  • 应用场景:反向代理、鉴权、流量控制、熔断、日志监控
  • 与Zuul的区别: 在这里插入图片描述

核心概念

  • 动态路由:能够匹配任何请求属性,是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如果断言为true则匹配该路由
  • 断言:参考的是JAVA8的java.util.function.Predicate,开发人员可以匹配HTTP请求中的所有内容,如果请求与断言相匹配则进行路由
  • 过滤:指的是Spring框架中的GatewayFilter的实例,使用过滤器,可以在请求被路由前或者后对请求进行修改
  • 核心逻辑:路由转发+执行过滤链

——实操

  • pom
        <!--        gateway-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
  • yml
server:
  port: 9527

spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true   # 开启从注册中心动态创建路由的功能,利用微服务名进行路由
      routes:
        - id: payment_routh             # 路由的id,没有固定的规则但要求统一,建议配合服务名
#          uri: http://localhost:8001    # 匹配后提供服务的路由地址
          uri: lb://cloud-payment-service
          predicates:   # 断言
            - Path=/payment/get/**    # 指定的路径才可生效
#            - After=2020-09-15T15:53:47.026+08:00[Asia/Shanghai]    # 在此时间之后生效
#            - Before=2020-09-15T15:53:47.026+08:00[Asia/Shanghai]   # 在此时间之前生效
#            - Between=2020-09-15T15:53:47.026+08:00[Asia/Shanghai],2020-09-15T16:53:47.026+08:00[Asia/Shanghai]   # 在此时间之间生效
#            - Cookie=username,xlj   # 只有cookie包含username,并且value为xlj才生效
#            - Header=X-Request-Id,\d+   # 包含指定请求头,value为数字
#            - Host=**.baidu.com   # 指定主机才可访问
#            - Method=GET    # 请求方法为GET才生效

        - id: payment_routh2             # 路由的id,没有固定的规则但要求统一,建议配合服务名
#          uri: http://localhost:8001    # 匹配后提供服务的  路由地址
          uri: lb://cloud-payment-service
          predicates:
            - Path=/payment/lb/**      # 断言,路径相对应的进行路由
eureka:
  instance:
    hostname: cloud-gateway-service
  client:
    service-url:
      fetch-registry: true
      # true将服务注册到eureka
      register-with-eureka: true
      #      集群Eureka
      defaultZone: http://eureka7001:7001/eureka,http://eureka7002:7002/eureka
#      单机版Eureka
#      defaultZone: http://localhost:7001/eureka

路由配置

  • yml文件配置
spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      routes:
        - id: payment_routh             # 路由的id,没有固定的规则但要求统一,建议配合服务名
          uri: http://localhost:8001    # 匹配后提供服务的路由地址
          predicates:
            - Path=/payment/get/**      # 断言,路径相对应的进行路由

        - id: payment_routh2             # 路由的id,没有固定的规则但要求统一,建议配合服务名
          uri: http://localhost:8001    # 匹配后提供服务的路由地址
          predicates:
            - Path=/payment/lb/**      # 断言,路径相对应的进行路由
  • 配置类
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder) {
        RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
        // 访问http://localhost:9527/guonei跳转到http://news.baidu.com/guonei
        routes.route("path_route_xlj", r -> r.path("/guonei").uri("http://news.baidu.com/guonei")).build();
        return routes.build();
    }
  • 通过微服务名实现动态路由
spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true   # 开启从注册中心动态创建路由的功能,利用微服务名进行路由
      routes:
        - id: payment_routh             # 路由的id,没有固定的规则但要求统一,建议配合服务名
#          uri: http://localhost:8001    # 匹配后提供服务的路由地址
          uri: lb://cloud-payment-service
          predicates:
            - Path=/payment/get/**      # 断言,路径相对应的进行路由

        - id: payment_routh2             # 路由的id,没有固定的规则但要求统一,建议配合服务名
#          uri: http://localhost:8001    # 匹配后提供服务的  路由地址
          uri: lb://cloud-payment-service
          predicates:
            - Path=/payment/lb/**      # 断言,路径相对应的进行路由

断言

predicates:   # 断言
            - Path=/payment/get/**    # 指定的路径才可生效
            - After=2020-09-15T15:53:47.026+08:00[Asia/Shanghai]    # 在此时间之后生效
            - Before=2020-09-15T15:53:47.026+08:00[Asia/Shanghai]   # 在此时间之前生效
            - Between=2020-09-15T15:53:47.026+08:00[Asia/Shanghai],2020-09-15T16:53:47.026+08:00[Asia/Shanghai]   # 在此时间之间生效
            - Cookie=username,xlj   # 只有cookie包含username,并且value为xlj才生效
            - Header=X-Request-Id,\d+   # 包含指定请求头,value为数字
            - Host=**.baidu.com   # 指定主机才可访问
            - Method=GET    # 请求方法为GET才生效

自定义配置过滤器

public class LogGatewayFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("*****come in LogGatewayFilter"+ new Date());
        String username = exchange.getRequest().getQueryParams().getFirst("username");
        if (StringUtils.isEmpty(username)){
            log.info("***用户名为空,非法进入");
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }

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