Spring Cloud Gateway 之 Predict

简介: 在之前的文章的Spring Cloud Gateway初体验中,大家已经对Spring Cloud Gateway的功能有一个初步的认识,网关作为一个系统的流量的入口,有着举足轻重的作用。

文章首发于公众号《程序员果果》
地址:https://mp.weixin.qq.com/s/2twx-aCEM2GXluDUIubGZg

Spring Cloud gateway工作流程

在之前的文章的Spring Cloud Gateway初体验中,大家已经对Spring Cloud Gateway的功能有一个初步的认识,网关作为一个系统的流量的入口,有着举足轻重的作用,通常的作用如下:

  • 协议转换,路由转发
  • 流量聚合,对流量进行监控,日志输出
  • 作为整个系统的前端工程,对流量进行控制,有限流的作用
  • 作为系统的前端边界,外部流量只能通过网关才能访问系统
  • 可以在网关层做权限的判断
  • 可以在网关层做缓存

Spring Cloud Gateway作为Spring Cloud框架的第二代网关,在功能上要比Zuul更加的强大,性能也更好。随着Spring Cloud的版本迭代,Spring Cloud官方有打算弃用Zuul的意思。在笔者调用了Spring Cloud Gateway的使用和功能上,Spring Cloud Gateway替换掉Zuul的成本上是非常低的,几乎可以无缝切换。Spring Cloud Gateway几乎包含了zuul的所有功能。

如上图所示,客户端向Spring Cloud Gateway发出请求。 如果Gateway Handler Mapping确定请求与路由匹配(这个时候就用到predicate),则将其发送到Gateway web handler处理。 Gateway web handler处理请求时会经过一系列的过滤器链。 过滤器链被虚线划分的原因是过滤器链可以在发送代理请求之前或之后执行过滤逻辑。 先执行所有“pre”过滤器逻辑,然后进行代理请求。 在发出代理请求之后,收到代理服务的响应之后执行“post”过滤器逻辑。这跟zuul的处理过程很类似。在执行所有“pre”过滤器逻辑时,往往进行了鉴权、限流、日志输出等功能,以及请求头的更改、协议的转换;转发之后收到响应之后,会执行所有“post”过滤器的逻辑,在这里可以响应数据进行了修改,比如响应头、协议的转换等。

在上面的处理过程中,有一个重要的点就是讲请求和路由进行匹配,这时候就需要用到predicate,它是决定了一个请求走哪一个路由。

Predicate 介绍

Predicate 来源于 Java 8,是 Java 8 中引入的一个函数,Predicate 接受一个输入参数,返回一个布尔值结果。该接口包含多种默认方法来将 Predicate 组合成其他复杂的逻辑(比如:与,或,非)。可以用于接口请求参数校验、判断新老数据是否有变化需要进行更新操作。

在 Spring Cloud Gateway 中 Spring 利用 Predicate 的特性实现了各种路由匹配规则,有通过 Header、请求参数等不同的条件来进行作为条件匹配到对应的路由。网上有一张图总结了 Spring Cloud 内置的几种 Predicate 的实现。

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

Predicate 实战

通过时间匹配

Predicate 支持设置一个时间,在请求进行转发的时候,可以通过判断在这个时间之前或者之后进行转发。比如我们现在设置只有在2019年2月15日才会转发到我的简书地址,在这之前不进行转发,我就可以这样配置:

spring:
  cloud:
    gateway:
      routes:
        - id: after_route
          uri: http://httpbin.org
          predicates:
          - After=2018-02-15T00:00:00+08:00[Asia/Shanghai]

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

After Route Predicate 是指在这个时间之后的请求都转发到目标地址。上面的示例是指,请求时间在 2019年2月15日0点0分0秒之后的所有请求都转发到地址http://httpbin.org。+08:00是指时间和UTC时间相差八个小时,时间地区为Asia/Shanghai

添加完路由规则之后,访问地址 http://127.0.0.1:8080/get 会自动转发到 http://httpbin.org/get

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

spring:
  cloud:
    gateway:
      routes:
        - id: before_route
          uri: http://httpbin.org
          predicates:
          - Before=2019-02-15T00:00:00+08:00[Asia/Shanghai]

就表示在2019-02-14之前可以进行路由,在这时间之后停止路由,修改完之后重启项目再次访问地址http://localhost:8080,页面会报 404 没有找到地址。

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

spring:
  cloud:
    gateway:
      routes:
        - id: between_route
          uri: http://httpbin.org
          predicates:
          - Between=2018-02-14T00:00:00+08:00[Asia/Shanghai], 2019-02-16T23:59:59+08:00[Asia/Shanghai]

这样设置就意味着在 2019-02-14到2019-02-16 时间段内可以匹配到此路由,超过这个时间段范围则不会进行匹配。通过时间匹配路由的功能很酷,可以用在限时抢购的一些场景中。

通过 Cookie 匹配

Cookie Route Predicate 可以接收两个参数,一个是 Cookie name ,一个是正则表达式,路由规则会通过获取对应的 Cookie name 值和正则表达式去匹配,如果匹配上就会执行路由,如果没有匹配上则不执行。

spring:
  cloud:
    gateway:
      routes:
        - id: cookie_route
          uri: http://httpbin.org:80
          predicates:
          - Cookie=name, chengxuyuanguoguo

上面的配置中,请求带有cookie名为name, cookie值为chengxuyuanguoguo 的请求将都会转发到uri为 http://httpbin.org的地址上。

使用 curl 测试,命令行输入:

curl http://127.0.0.1:8080/get --cookie "name=chengxuyuanguoguo"

则有正确返回,如果去掉--cookie "name=chengxuyuanguoguo",没有匹配成功,出现 404 错误。

通过 Header 属性匹配

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

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

使用 curl 测试,命令行输入:

curl http://127.0.0.1:8080/get  -H "X-Request-Id:111111" 

则正常返回,将参数 "X-Request-Id:111111" 改为 "X-Request-Id:xxxx" 再次执行时返回404。

通过 Host 匹配

Host Route Predicate 接收一组参数,一组匹配的域名列表,这个模板是一个 ant 分隔的模板,用.号作为分隔符。它通过参数中的主机地址作为匹配规则。

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

使用 curl 测试,命令行输入:

curl http://127.0.0.1:8080/get  -H "Host:www.httpbin.com" 

测试上述 host 可匹配到 host_route 路由,去掉 host 参数则会报 404 错误。

通过请求方式匹配

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

spring:
  cloud:
    gateway:
      routes:
        - id: method_route
          uri: http://httpbin.org
          predicates:
          - Method=GET

使用 curl 测试,命令行输入:

curl http://127.0.0.1:8080/get

测试返回正确,证明匹配到路由,再以 POST 的方式请求测试:

curl -X POST http://127.0.0.1:8080/get

返回 404 没有找到,没有匹配上路由。

通过请求路径匹配

Path Route Predicate 接收一个匹配路径的参数来判断是否走路由。

spring:
  cloud:
    gateway:
      routes:
        - id: path_route
          uri: http://httpbin.org
          predicates:
            - Path=/foo/{segment}

使用 curl 测试,命令行输入:

curl http://127.0.0.1:8080/foo/1
curl http://127.0.0.1:8080/fee/1

测试第一命令可以正常获取到页面返回值,第二个命令报404,证明路由是通过指定路由来匹配。

通过请求参数匹配

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

spring:
  cloud:
    gateway:
      routes:
        - id: query_route
          uri: http://httpbin.org
          predicates:
          - Query=foo

测试发现只要请求带有 foo 参数即会匹配路由,不带 foo 参数则会报 404 错误。

通过请求 ip 地址进行匹配

Predicate 也支持通过设置某个 ip 区间号段的请求才会路由,RemoteAddr Route Predicate 接受 cidr 符号(IPv4 或 IPv6 )字符串的列表(最小大小 1),例如 192.168.0.1/16 (其中 192.168.0.1 是 IP 地址,16 是子网掩码)。

spring:
  cloud:
    gateway:
      routes:
        - id: remoteaddr_route
          uri: http://httpbin.org
          predicates:
          - RemoteAddr=172.16.1.73/24

使用 curl 测试,命令行输入:

curl http://172.17.1.73:8080/get

测试返回正确,改为请求 127.0.0.1:8080/get 则会报 404 错误。

组合使用

Predicate还可以组合在一起使用。

spring:
  cloud:
    gateway:
      routes:
        - id: group_route
          uri: http://httpbin.org
          predicates:
          - Host=**.httpbin.com
          - Header=X-Request-Id, \d+
          - Cookie=name, chengxuyuanguoguo
          - After=2019-02-15T00:00:00+08:00[Asia/Shanghai]

使用 curl 测试,命令行输入:

curl http://127.0.0.1:8080 -H "X-Request-Id:111111" -H "Host:www.httpbin.com" --cookie "name=chengxuyuanguoguo"

测试返回正确,错误的规则或去除一个规则,则会报 404 错误。

总结

Predict作为断言,它决定了请求会被路由到哪个router 中。在断言之后,请求会被进入到filter过滤器的逻辑,下篇文章将会介绍Spring Cloud Gateway过滤器相关的内容。

源码

https://github.com/gf-huanchupk/SpringCloudLearning/tree/master/chapter13/springcloud-gateway-predict

相关文章
|
3月前
|
负载均衡 Java Nacos
SpringCloud基础2——Nacos配置、Feign、Gateway
nacos配置管理、Feign远程调用、Gateway服务网关
SpringCloud基础2——Nacos配置、Feign、Gateway
|
3月前
|
Java 开发者 Spring
Spring Cloud Gateway 中,过滤器的分类有哪些?
Spring Cloud Gateway 中,过滤器的分类有哪些?
72 3
|
3月前
|
负载均衡 Java 网络架构
实现微服务网关:Zuul与Spring Cloud Gateway的比较分析
实现微服务网关:Zuul与Spring Cloud Gateway的比较分析
138 5
|
2月前
|
负载均衡 Java API
【Spring Cloud生态】Spring Cloud Gateway基本配置
【Spring Cloud生态】Spring Cloud Gateway基本配置
44 0
|
3月前
|
安全 Java 开发者
强大!Spring Cloud Gateway新特性及高级开发技巧
在微服务架构日益盛行的今天,网关作为微服务架构中的关键组件,承担着路由、安全、监控、限流等多重职责。Spring Cloud Gateway作为新一代的微服务网关,凭借其基于Spring Framework 5、Project Reactor和Spring Boot 2.0的强大技术栈,正逐步成为业界的主流选择。本文将深入探讨Spring Cloud Gateway的新特性及高级开发技巧,助力开发者更好地掌握这一强大的网关工具。
257 6
|
5月前
|
负载均衡 Java Spring
Spring cloud gateway 如何在路由时进行负载均衡
Spring cloud gateway 如何在路由时进行负载均衡
543 15
|
5月前
|
Java Spring
spring cloud gateway在使用 zookeeper 注册中心时,配置https 进行服务转发
spring cloud gateway在使用 zookeeper 注册中心时,配置https 进行服务转发
117 3
|
5月前
|
Java 微服务 Spring
SpringCloud gateway自定义请求的 httpClient
SpringCloud gateway自定义请求的 httpClient
210 3
|
4月前
|
Java 应用服务中间件 nginx
【Azure Spring Apps】Spring App部署上云遇见 502 Bad Gateway nginx
【Azure Spring Apps】Spring App部署上云遇见 502 Bad Gateway nginx
|
5月前
|
JSON 前端开发 Java
SpringCloud怎么搭建GateWay网关&统一登录模块
本文来分享一下,最近我在自己的项目中实现的认证服务,目前比较简单,就是可以提供一个公共的服务,专门来处理登录请求,然后我还在API网关处实现了登录拦截的效果,因为在一个博客系统中,有一些地址是可以不登录的,比方说首页;也有一些是必须登录的,比如发布文章、评论等。所以,在网关处可以支持自定义一些不需要登录的地址,一些需要登录的地址,也可以在网关处进行校验,如果未登录,可以返回JSON格式的出参,前端可以进行相关处理,比如跳转到登录页面等。
134 4