GateWay网关

概述简介

Gateway是在 Spring生态系统之上构建的AP网关服务,基于 Spring5, Spring Boot2和 Project Reactor等技术。
Gateway旨在提供一种简单而有效的方式来对API进行路由,以及提供一些强大的过滤器功能,例如:熔断、限流、重试
官网地址:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.2.RELEASE/reference/html/
SpringCloud(四)GateWay网关-LMLPHP
SpringCloud Gateway是 Spring Cloud的个全新项目,基于 Spring5.0+ Spring Boot2.0和 Project Reactor等技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的API路由管理方式
SpringCloud Gateway作为 Spring Cloud生态系统中的网关,目标是替代zuul,在 Spring Cloud2.0以上版本中,没有对新版本的zuul2.0以上最新高性能版本进行集成,仍然还是使用的zuul1.×非 Reactor模式的老版本。Spring Cloud Gateway使用的 Webflux中的 reactor-netty响应式编程组件,底层使用了 Netty通讯框架
Spring Cloud Gateway的目标提供统-的路由方式且基于 Filter 链的方式提供了网关基本的功能,例如:安全,监控/指标,和限流

主要特点

作用:反向代理,鉴权,流量控制,熔断,日志监控

  • 基于 Spring Framework5, Project Reactor和 Spring Boot2.0进行构建
  • 动态路由:能够匹配任何请求属性
  • 可以对路由指定 Predicate(断言)和 Filter(过滤器)
  • 集成 Hystrix的断路器功能
  • 集成 Spring Cloud服务发现功能
  • 请求限流功能
  • 支持路径重写

三大核心概念

Route(路由)
路由是构建网关的基本模块,它由 ID,目标URI,一系列的断言和过滤器组成,如果断言为 true 则匹配该路由
Predicate(断言)
开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由
Filter(过滤)
指的是 Spring框架中 Gateway Filter的实例,使用过滤器,可以在请求被路由前或者之后对请求进行修改
web请求,通过一些匹配条件,定位到真正的服务节点。并在这个转发过程的前后,进行一些精细化控制,predicate就是我们的匹配条件,而 Filter ,就可以理解为个无所不能的拦截器有了这两个元素,再加上目标 uri 就可以实现一个具体的路由了
SpringCloud(四)GateWay网关-LMLPHP
客户端向 Spring Cloud Gateway 发出请求,然后在 Gateway Handler Mapping 中找到与请求相匹配的路由,将其发送到 Gateway Web handler,Handler再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回,过滤器之间用虚线分开是因为过滤器可能会在发送代理请求之前("pre")或之后("post")执行业务逻辑
Filter在"pre"类型的过滤器可以做参数校验、权限校验、流量监控、日志输岀、协议转换等,在"post”类型的过滤器中可以做响应内容、响应头的修改,日志的输出,流量监控等有着非常重要的作用

路由配置

  1. 创建一个新的 module
  2. 导入 GateWay 依赖
<!-- Gateway -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
    <version>2.2.2.RELEASE</version>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </exclusion>
    </exclusions>
</dependency>
  1. 配置路由映射
  • 第一种配置方式:在配置文件 yml 中配置
server:
  port: 9527

spring:
  application:
    name: GateWay-Service
  cloud:
    gateway:
      routes:
        # 路由的 ID,没有固定规则但要求唯一,建议配合服务名
        - id: payment-route1
        # 匹配后提供服务的路由地址
          uri: http://localhost:8001
        # 断言,路径相匹配的进行路由
        # 配置服务端的方法路径
          predicates:
            - Path=/payment/query/**

        - id: payment-route2
          uri: http://localhost:8001
          predicates:
            - Path=/payment/discovery/**

# Eureka
eureka:
  client:
    # 表示是否将自己注册到 EurekaServer
    register-with-eureka: true
    # 是否从 EurekaServer 抓取已有的注册信息
    # 单节点无所谓,集群必须设置为 true 才能配合 ribbon 使用
    fetch-registry: true
    service-url:
      # 单机版
      # defaultZone: http://localhost:7001/eureka/
      # 集群版
      defaultZone: http://eureka7001.com:7001/eureka, http://eureka7002.com:7002/eureka
  instance:
    hostname: GateWay-Service

SpringCloud(四)GateWay网关-LMLPHP

  • 第二种配置方式:自定义配置文件
@Configuration
public class GateConfig {

    /**
     * 测试通过网关 跳转到 百度新闻 的页面 http://news.baidu.com/guonei
     * 配置了一个 id 为 payment-route3 的路由规则
     * 当访问地址为 http://localhost:9527/guonei 会自动转发到 http://news.baidu.com/guonei
     * @param routeLocatorBuilder
     * @return
     */
    @Bean
    public RouteLocator routeLocator(RouteLocatorBuilder routeLocatorBuilder){
        return routeLocatorBuilder.routes()
                .route( "payment-route3",r -> {
                    return r.path("/guonei")
                            .uri("http://news.baidu.com/guonei");
                })
                .build();
    }
}

SpringCloud(四)GateWay网关-LMLPHP

动态路由

默认情况下 Gateway会根据注册中心注册的服务列表,以注册中心上微服名为路径创建动态路由进行转发,从而实现动态路由的功能
配置 yml 配置文件
需要注意的是 uri 的协议为lb,表示启用 Gateway的负载均衡功能
lb://service Name 是spring cloud gateway在微服务中自动为我们创建的负载均衡uri

spring:
  application:
    name: GateWay-Service
  cloud:
    gateway:
      discovery:
        locator:
          # 开启从注册中心动态创建路由的功能,利用微服务名进行路由
          enabled: true
      routes:
        # 路由的 ID,没有固定规则但要求唯一,建议配合服务名
        - id: payment-route1
        # 匹配后提供服务的路由地址
        # uri: http://localhost:8001 不能写死
        # 匹配 服务端 的路由地址,就是微服务名
          uri: lb://provider-payment-service
        # 断言,路径相匹配的进行路由
        # 配置服务端的方法路径
          predicates:
            - Path=/payment/lb/**

        - id: payment-route2
          uri: lb://provider-payment-service
          predicates:
            - Path=/payment/query/**

开启两个服务端8001和8002
实现了动态路由,可以测试到此时端口可以互相切换

Predicate使用

当开启路由网关时
SpringCloud(四)GateWay网关-LMLPHP
SpringCloud Gateway 将路由匹配作为 Spring WebFlux HandlerMapping基础架构的部分
SpringCloud Gateway 包括许多内置的 RoutePredicate 工厂。所有这些Predicate都与HTTP请求的不同属性匹配,多个Route Predicate工厂可以进行组合
Spring Cloud Gateway创建 Route对象时,使用 RoutePredicate Factory创建 Predicate对象, Predicate对象可以赋值给Route. Spring Cloud Gateway包含许多内置的 Route predicate factories
所有这些谓词都匹配HTTP请求的不同属性。多种谓词工厂可以组合,并通过逻辑and组合

常用的 Route Predicate
After

路由规则可以匹配一个时间,设置在{arg}之后,当请求的时间在配置时间之后,才会交给 route 去处理

spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: https://example.org
        predicates:
        - After=2021-01-20T17:42:47.789-07:00[China/Shanghai]
Before

路由规则可以匹配一个时间,设置在{arg}之前,当请求的时间在配置时间之前,才会交给 route 去处理

spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: https://example.org
        predicates:
        - Before=2021-01-20T17:42:47.789-07:00[China/Shanghai]
Between

路由规则可以匹配一个时间,设置在{arg}之间,当请求的时间在配置时间之间,才会交给 route 去处理

spring:
  cloud:
    gateway:
      routes:
      - id: between_route
        uri: https://example.org
        predicates:
        - Between=2021-01-20T17:42:47.789-07:00[China/Shanghai], 2021-01-21T17:42:47.789-07:00[China/Shanghai]
Cookie

需要2个参数,一个是cookie名字,另一个是值,可以为正则表达式。它用于匹配请求中,带有该名称的cookie和cookie匹配正则表达式的请求

spring:
  cloud:
    gateway:
      routes:
      - id: cookie_route
        uri: https://example.org
        predicates:
        - Cookie=name, zhangsan

# 例
# 请求带有cookie名为name, cookie值为 zhangsan 的请求
# 将都会转发到uri为 https://example.org 的地址上

# curl 请求
# $ curl -H ‘Cookie:name=zhangsan’ localhost:8081
  • 不带cookie访问
    SpringCloud(四)GateWay网关-LMLPHP

  • 带cookie访问
    SpringCloud(四)GateWay网关-LMLPHP

Header

在上面的配置中,当请求的 Header 中有 X-Request-Id的header名,且header值为数字时,请求会被路由到配置的 uri

spring:
  cloud:
    gateway:
      routes:
      - id: header_route
        uri: https://example.org
        predicates:
        - Header=X-Request-Id, \d+

# 例
# $ curl -H ‘X-Request-Id:1’ localhost:8081

SpringCloud(四)GateWay网关-LMLPHP

Host

需要一个参数即hostname,它可以使用 . 或者 * 等去匹配host。这个参数会匹配请求头中的host的值,一致,则请求正确转发

spring:
  cloud:
    gateway:
      routes:
      - id: host_route
        uri: https://example.org
        predicates:
        - Host=**.somehost.org,**.anotherhost.org

# 如果请求的主机标头的值为
    www.somehost.org
    或 beta.somehost.org
    或 www.anotherhost.org
# 则此路由匹配
# curl 请求
# curl -H ‘Host:www.adou.com’ localhost:8081

SpringCloud(四)GateWay网关-LMLPHP

Method

如果请求方法是GET或POST,则此路由匹配

spring:
  cloud:
    gateway:
      routes:
      - id: method_route
        uri: https://example.org
        predicates:
        - Method=GET,POST
Path

当请求路径满足 /red/** ,则会经过 route 到达 https://example.org

spring:
  cloud:
    gateway:
      routes:
      - id: path_route
        uri: https://example.org
        predicates:
        - Path=/red/**
Query

也可以只填一个参数,填一个参数时,则只匹配参数名,当请求中请求参数包含 green,则会经过 route 到达 https://example.org

spring:
  cloud:
    gateway:
      routes:
      - id: query_route
        uri: https://example.org
        predicates:
        - Query=green
        - Query=color, green
# 配置了请求中含有参数color,并且color的值匹配green.,则请求命中路由
# curl 请求
# $ curl localhost:8081?color=green
RemoterAddr

请求远程地址,则会经过 route

spring:
  cloud:
    gateway:
      routes:
      - id: remoteaddr_route
        uri: https://example.org
        predicates:
        - RemoteAddr=192.168.1.1/24

# 如果请求的远程地址是 192.168.1.10 ,则此路由匹配
Weight

权重采用两个参数匹配 group 和 weight,当达成条件则会路由转发

spring:
  cloud:
    gateway:
      routes:
      - id: weight_high
        uri: https://weighthigh.org
        predicates:
        - Weight=group1, 8
      - id: weight_low
        uri: https://weightlow.org
        predicates:
        - Weight=group1, 2

# 这条路线会将大约80%的流量转发到 weighthigh.org
# 将大约20%的流量转发到 weightlow.org

说白了, Predicate就是为了实现一组匹配规则,让请求过来找到对应的 Route进行处理

Filter使用

路由过滤器可用于修改进入的HTTP请求和返回的HTTP响应,路由过滤器只能指定路由进行使用
Spring Cloud Gateway内置了多种路由过滤器,他们都由 GatewayFilter 的工厂类来产生
种类:GateWayFilterGlobalFilter

自定义过滤器
自定义全局GlobalFilter
主要继承两个接口:GlobalFilter,Ordered
作用:全局日志记录,统一网关鉴权等等

@Component
@Slf4j
public class LogGateWayFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 获取请求的参数
        String username = exchange.getRequest().getQueryParams().getFirst("username");
        if (username == null){
            log.info("用户名为空,找不到该用户");
            // 设置状态码
            exchange.getResponse().setStatusCode(HttpStatus.NOT_FOUND);
            return exchange.getResponse().setComplete();
        }
        // 返回
        log.info("进入拦截器");
        return chain.filter(exchange);
    }

    /**
     * 加载过滤器的顺序
     * @return
     */
    @Override
    public int getOrder() {
        return 0;
    }
}

SpringCloud(四)GateWay网关-LMLPHP

05-03 17:49