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

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

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

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

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条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章