您现在的位置是:首页 > 文章详情

使用 Spring cloud Gateway 构建微服务网关

日期:2020-06-30点击:698

云栖号资讯:【点击查看更多行业资讯
在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来!

image

使用 Spring cloud Gateway 构建微服务网关

Spring Cloud Gateway 是 Spring Cloud 的一个子项目,该项目是基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。

Spring Cloud Gateway 作为 Spring Cloud 生态系统中的网关,目标是替代 Netflix Zuul,其不仅提供统一的路由方式,并且基于 Filter 的方式提供了网关基本的功能,例如:安全,监控/指标,和限流。

相关概念

  • Route(路由):网关的基本构件块,类似于 nginx 的 location 配置。由一个 ID、一个目标 URI、一组 Predicate 和一组 Filter 定义
  • Predicate(断言):路由组成的一部分,主要负责路由的匹配,来决定此次请求是否匹配路由,我们可以使用它匹配来自 HTTP 请求的任何内容,比如路径、参数或者 header 信息等等
  • Filter(过滤器):这个是 GatewayFilter 的实例,请求经过 Predicate 匹配路由之后执行 Filter,我们可以使用它修改请求和响应。

快速上手

Spring Cloud Gateway 网关路由有两种配置方式:

  • 通过配置文件配置
  • 通过 @Bean 自定义 RouteLocator 去配置

这两种方式是等价的,建议使用配置文件配置。因为 Spring Cloud Gateway 使用响应式编程框架,学习曲线相对陡峭。

引入依赖:

    <properties>
        <java.version>1.8</java.version>
        <!-- springcloud 版本 -->
        <spring-cloud.version>Hoxton.SR1</spring-cloud.version>
    </properties>
    <dependencies>
        <!-- 服务注册发现相关 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- gateway 依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
    </dependencies>
Spring cloud gateway 是使用 netty+webflux 实现,因此不需要再引入 web 模块。

配置文件:

server:
  port: 8088
eureka:
  client:
    serviceUrl:
      # 注册中心地址
      defaultZone: http://dev-crm-host001.ymt.io:8761/eureka
spring:
  application:
    name: test-gateway
  cloud:
    gateway:
      routes:
        - id: test1
          uri: http://www.baidu.com
          predicates:
            - Path=/baidu/**
          filters:
            - StripPrefix=1

各字段含义如下:

  • id:我们自定义的路由 ID,保持唯一
  • uri:目标服务地址,大部分场景我们是转发到某个服务上,配置 uri: lb://user-service 意思是请求要转发到注册中心的 user-service 服务上。
  • predicates:路由条件,接受一个参数,返回一个布尔结果决定是否匹配。Gateway 为我们内置了多种路由条件,包括 Path、Cookie、Param、Header、Before、After 等等,开箱即用,当然我们也可以自己实现 predicates
  • filters:过滤规则,当请求经过 predicate 匹配成功后,执行 filter,我们可以使用它修改请求和响应,示例表示目标服务收到的 path 将无第一级。

启动程序,当我们访问 localhost:8088/baidu 时,gateway 会根据我们配置的路由规则转发到 https://www.baidu.com

路由规则:Predicate 介绍

Spring Cloud Gateway 的功能很强大,我们仅仅通过 Predicates 的设计就可以看出来,前面我们只是使用了 predicates 进行了简单的条件匹配,Spring Cloud Gateway 内置了很多 Predicates 工厂,这些 Predicates 工厂通过不同的 HTTP 请求参数来匹配,多个 Predicates 工厂可以组合使用。

网上有一张图总结了 Spring Cloud 内置的集中 Predicate:

image

说白了 Predicate 就是实现了一组匹配规则,方便让请求过来找到对应的 Route 进行处理。接下来介绍一下内置几种 Predicate 的使用。

通过时间匹配

Predicate 支持设置一个时间,在请求进行转发的时候,可以通过判断在这个时间之前或者之后进行转发。比如我们现在设置只有在 2020 年 1 月 1 日才会转发到 https://www.baidu.com/,在这之前不进行转发,我就可以这样配置:

spring:
  cloud:
    gateway:
      routes:
        - id: time_route
            uri: http://www.baidu.com
            predicates:
          - After=2020-01-01T01:01:01+08:00[Asia/Shanghai]

Spring 是通过 ZonedDateTime 来对时间进行的对比,ZonedDateTime 是 Java 8 中日期时间功能里,用于表示带时区的日期与时间信息的类,ZonedDateTime 支持通过时区来设置时间,中国的时区是:Asia/Shanghai。

Before Predicate 刚好相反,在某个时间之前的请求的请求都进行转发。我们把上面路由规则中的 After 改为 Before,如下:

spring:
  cloud:
    gateway:
      routes:
        - id: time_route
          uri: http://www.baidu.com
          predicates:
          - Before=2020-01-01T01:01:01+08:00[Asia/Shanghai]

就表示在这个时间之前可以进行路由,在这时间之后停止路由。

除过在时间之前或者之后外,Gateway 还支持限制路由请求在某一个时间段范围内,可以使用 Between Predicate 来实现。

spring:
  cloud:
    gateway:
      routes:
        - id: after_route
            uri: http://www.baidu.com
            predicates:
          - Between=2019-01-01T01:01:01+08:00[Asia/Shanghai], 2020-01-01T01:01:01+08:00[Asia/Shanghai]

通过 Cookie 匹配

Cookie Route Predicate 可以接收两个参数,一个是 Cookie name,一个是正则表达式。

spring:
  cloud:
    gateway:
      routes:
        - id: cookie_route
            uri: http://www.baidu.com
            predicates:
          - Cookie=name, ymt

通过 Header 属性匹配

Header Route Predicate 和 Cookie Route Predicate 一样,也是接收 2 个参数,一个 header 中属性名称和一个正则表达式。

spring:
  cloud:
    gateway:
      routes:
        - id: header_route
            uri: http://www.baidu.com
            predicates:
          - Header=name, ymt

通过 Host 匹配

spring:
  cloud:
    gateway:
      routes:
        - id: host_route
          uri: http://www.baidu.com
          predicates:
          - Host=**.baidu.com

通过 Request Method 匹配

可以通过是 POST、GET、PUT、DELETE 等不同的请求方式来进行路由。

spring:
  cloud:
    gateway:
      routes:
        - id: method_route
          uri: http://www.baidu.com
          predicates:
          - Method=GET

通过请求路径匹配

之前示例是使用的请求路径去匹配的。

spring:
  cloud:
    gateway:
      routes:
        - id: test1
          uri: http://www.baidu.com
          predicates:
          - Path=/baidu/**
          filters:
          - StripPrefix=1

通过请求参数匹配

Query Route Predicate 支持传入两个参数,一个是属性名一个为属性值,属性值可以是正则表达式。

spring:
  cloud:
    gateway:
      routes:
        - id: query_route
          uri: http://www.baidu.com
          predicates:
          - Query=type,baidu

如上图所示,输入 localhost:8088/?type=baidu 会被转发到 https://www.baidu.com/?type=baidu

如果写成 - Query=type,这样配置,只要请求中包含 type 属性的参数即可匹配路由。

通过请求 ip 地址进行匹配

spring:
  cloud:
    gateway:
      routes:
        - id: remoteaddr_route
          uri: http://www.baidu.com
          predicates:
          - RemoteAddr=192.168.1.1/24

组合使用

以上示例演示了单个 Predicate 的使用,Predicate 也可以放在一起组合使用。

spring:
  cloud:
    gateway:
      routes:
       - id: combination_route
       uri: http://ityouknow.com
       predicates:
       - RemoteAddr=192.168.1.1/24
       - Query=type,baidu
       - Path=/baidu/**

各种 Predicates 同时存在于同一个路由时,请求必须同时满足所有的条件才被这个路由匹配。

一个请求满足多个路由的 Predicate 条件时,请求只会被首个成功匹配的路由转发

如何自己实现 Predicate

以上介绍了内置的 Predicate 的使用,但是在一些特殊的场景下,内置的 Predicate 可能满足不了我们的需求,这个时候我们就可以根据 Gateway 提供的接口实现自己的 Predicate。

需求背景

系统中有一些请求需要根据参数去转发,比如根据查询参数的某一个范围去转发,例如 /server?type=A,当 type 为 A、B、C 三个其中一个值时转发到 server1 服务,type 为 D、E、F 三个其中一个值时转发到 server2 服务。我们可以通过继承 org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory 实现

/**
 * 工作流相关的断言
 *
 * @author zhangtao
 * @since 2020-01-06 7:26 下午
 */
@Component
public class TypeRoutePredicateFactory extends AbstractRoutePredicateFactory<WorkFlowRoutePredicateFactory.Config> {
    public WorkFlowRoutePredicateFactory() {
        super(WorkFlowRoutePredicateFactory.Config.class);
    }
    private static final String DATETIME_KEY = "type";
    @Override
    public List<String> shortcutFieldOrder() {
        return Collections.singletonList(DATETIME_KEY);
    }
    // 配置参数的类型,此时指定为List
    @Override
    public ShortcutType shortcutType() {
        return ShortcutType.GATHER_LIST;
    }
    // 判断的逻辑,如果返回为true则匹配成功
    @Override
    public Predicate<ServerWebExchange> apply(WorkFlowRoutePredicateFactory.Config config) {
        return new GatewayPredicate() {
            @Override
            public boolean test(ServerWebExchange exchange) {
                // 判断参数中是否有配置的type
                List<String> types = exchange.getRequest().getQueryParams().get("type");
                if (types != null && types.size() == 1 && config.getType().contains(types.get(0))) {
                    return true;
                }
                return false;
            }
        };
    }
    @Validated
    public static class Config {
        private List<String> type = new ArrayList<>();
        public List<String> getType() {
            return type;
        }
        public void setType(List<String> type) {
            this.type = type;
        }
    }
}

配置文件:

spring:
  cloud:
    gateway:
      routes:
      - id: server1-route
        uri: http://www.baidu.com
        predicates:
        # Type为,TypeRoutePredicateFactory类 RoutePredicateFactory前面的值
        - Type=A,B,C
      - id: server2-route
        uri: https://cn.bing.com/
        predicates:
        # Type为,TypeRoutePredicateFactory类 RoutePredicateFactory前面的值
        - Type=D,E,F

以上配置为,当请求参数中 type 的值为 A、B、C 其中一个时则匹配成功,通过 server1-route 路由转发到 http://www.baidu.com,当请求参数中 type 的值为 D、E、F 其中一个时则匹配成功,通过 server2-route 路由转发到 https://cn.bing.com/

总结

Spring Cloud Gateway 使用非常的灵活,可以根据不同的情况来进行路由分发,在实际项目中可以自由组合使用。同时 Spring Cloud Gateway 还有更多很酷的功能,比如 Filter、熔断和限流等。

【云栖号在线课堂】每天都有产品技术专家分享!
课程地址:https://yqh.aliyun.com/live

立即加入社群,与专家面对面,及时了解课程最新动态!
【云栖号在线课堂 社群】https://c.tb.cn/F3.Z8gvnK

原文发布时间:2020-07-01
本文作者:张sir
本文来自:“infoq”,了解相关信息可以关注“infoq

原文链接:https://yq.aliyun.com/articles/766417
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章