1. 首页
  2. >
  3. 技术专题
  4. >
  5. SpringCloud

SpringCloud系列Gateway:路由匹配规则

环境搭建

主要分三个项目

  1. Product-service(端口8890):商品服务
  2. Order-service(端口8891):订单服务
  3. Gateway-server(端口8892):网关

SpringCloud系列Gateway:路由匹配规则

核心概念

  1. 路由(Route):路由是网关最基础的部分,路由信息ID、目标URI、一组断言和一组过滤器组成,如果断言为真,说明请求的URI和配置匹配。
  2. 断言(Predicate):Spring Cloud Gateway中的断言函数输入类型是Spring5.0框架中的ServerWebExchange。Spring Cloud Gateway中的断言函数允许开发者去定义匹配来自于Http Request中的任何信息,比如请求头和参数等。
  3. 过滤器(Filter):一个标准的Spring Web Filter。Spring Cloud Gateway中的Filter分为两种类型,分别是Gateway Filter和Global Filter。过滤器将会对请求和相应进行处理。

工作原理

SpringCloud系列Gateway:路由匹配规则

如上图所示,客户端向Spring Cloud Gateway 发出请求,再由网关处理程序 Gateway Handler Mapping 映射确定与请求相匹配的路由,将其发送到网关Web处理程序Gateway Web Handler,该处理程序通过制定的过滤器链将请求发送到我们实际的服务执行逻辑,然后返回,过滤器有虚线分割的原因是,过滤器可以在发送代理请求之前和之后运行逻辑,所有pre过滤器逻辑均被执行,然后发出代理请求,发出代理请求后,将运行post过滤器逻辑。

路由规则

Spring Cloud Gateway创建Route对象时,使用RoutePredicateFactory创建Predicate对象,Predicate对象作为Route参数

  • Spring Cloud Gateway 包含许多内置的Route Predicate Factories。
  • 所有这些断言都匹配HTTP请求的不同属性
  • 多个Route Predicate Factories 可以通过逻辑与结合起来一起使用

路由断言工厂RoutePredicateFactory包含的主要实现类如下图所示,包含Datetime、Cookies、请求头、请求的远程地址、Host地址、请求方法、请求路径、请求参数和路由权重等路由断言。

SpringCloud系列Gateway:路由匹配规则

下面我们针对Path、Query、Method、Datetime、RemoteAddr和Header路由断言做一下讲解

Path

# 应用名称 spring:   cloud:     gateway:       routes:         - id: product-service    # 路由ID 唯一               uri: http://localhost:8890  # 目标URL,路由到对应的微服务地址           predicates:                # 断言             - Path=/product/**         # 匹配对应URL请求
  • 请求http://localhost:8892/product/1 将会路由至http://localhost:8890/product/1

Query

Query断言有两个参数:必填的param和可选的regexp(其实是Java正则表达式)。以下示例为配置Query路由规则:

# 应用名称 spring:   profiles: Query   cloud:     gateway:       routes:         - id: product-service         # 路由ID 唯一           uri: http://localhost:8890   # 目标URL,路由到对应的微服务地址           predicates:                 # 断言             - Query=token             # 匹配请求参数中包含token的请求

如果请求中包含参数token,将有该路由规则处理。

  • 请求http://localhost:8892/product/1?token=aa将会路由至http://localhost:8890/product/1?token=aa
  • 请求http://localhost:8892/product/1?auth=aa 请求参数中没有包括token,提示404错误
spring:   profiles: Query   cloud:     gateway:       routes:         - id: product-service         # 路由ID 唯一           uri: http://localhost:8890   # 目标URL,路由到对应的微服务地址           predicates:                 # 断言             - Query=token, abc.        # 匹配请求参数中包含token并且参数正则表达式是abc.的请求

如果请求中包含参数token,其值与abc.的正则表达式相匹配,将有该路由规则处理。

  • 请求http://localhost:8892/product/1?token=abcdd将会路由至http://localhost:8890/product/1?token=abcdd
  • 请求http://localhost:8892/product/1?token=ab 请求参数中的token值与abc.不匹配,提示404错误

Method

Method断言需要设置methods(GET、POST等)的参数,它可以是一个或多个参数。以下示例配置Method路由规则:

spring:   profiles: Method   cloud:     gateway:       routes:         - id: product-service         # 路由ID 唯一           uri: http://localhost:8890   # 目标URL,路由到对应的微服务地址           predicates:                 # 断言             - Method=GET              # 匹配任意GET请求
  • GET请求http://localhost:8892/product/1将会路由到http://localhost:8890/product/1
  • POST请求http://localhost:8892/product/1 该路由规则只支持GET请求,提示404错误

Datetime

Datetime断言包括After,Before和Between

  1. After

After断言规则有一个参数:datetime(类型为Java ZonedDateTime)。该规则匹配在指定日期时间之后发生的请求。

  1. Before

Before断言规则有一个参数:datetime(类型为Java ZonedDateTime)。该规则匹配在指定日期时间之前发生的请求。

  1. Between

Between断言规则有两个参数:datetime1和datetime2(类型为Java ZonedDateTime)。该规则匹配之后datetime1和之前发生的请求datetime2。

以After为例演示

# 应用名称 spring:   profiles: Datetime-after   cloud:     gateway:       routes:         - id: product-service         # 路由ID 唯一           uri: http://localhost:8890   # 目标URL,路由到对应的微服务地址           predicates:                 # 断言             - After=2020-12-06T20:33:01.000+08:00[Asia/Shanghai]             # 匹配中国上海2020年12月6日  20:33:01之后的请求

匹配中国上海2020年12月6日 20:33:01之后发的所有请求都能匹配

RemoteAddr

RemoteAddr用于限定远程请求地址

# 应用名称 spring:   profiles: RemoteAddr   cloud:     gateway:       routes:         - id: product-service         # 路由ID 唯一           uri: http://localhost:8890   # 目标URL,路由到对应的微服务地址           predicates:                 # 断言             - RemoteAddr=192.168.56.1/0           # 匹配远程地址为RemoteAddr的请求, 0表示子网掩码
  • http://192.168.56.1:8892/product/1将会路由至http://localhost:8890/product/1
  • http://localhost:8892/product/1 只能匹配远程地址为192.168.56.1的请求,当用localhost请求时将提示404错误

Header

Header断言规则包含两个参数:请求头name和一个regexp(其是Java正则表达式)。

spring:   profiles: Header   cloud:     gateway:       routes:         - id: product-service         # 路由ID 唯一           uri: http://localhost:8890   # 目标URL,路由到对应的微服务地址           predicates:                 # 断言             - Header=X-Request-Id, \d+           # 匹配请求头中带有X-Request-Id,并且值匹配正则表达式\d+的请求

匹配请求头中带有X-Request-Id并且值匹配正则表达式\d+的请求。

动态路由

动态获取URI

动态路由其实就是面向服务的路由,Spring Cloud Gateway支持与Nacos整合开发,根据serviceId自动从注册中心获取服务地址并转发请求,这样做的好处不仅可以通过单个端点来访问应用的所有服务,而且在添加和移除服务实例时不用修改Gateway的路由配置。

  1. 添加依赖项
<dependency>     <groupId>com.alibaba.cloud</groupId>     <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>
  1. 修改配置文件,设置spring.cloud.gateway.routes.uri=lb://product-service
server:   port: 8892 spring:   application:     name: gateway-server   cloud:     # 配置注册中心     nacos:       discovery:         server-addr: localhost:8848  # 注册中心地址         namespace: public			# 命名空间     gateway:       routes:         - id: product-service         # 路由ID 唯一           uri: lb://product-service   # lb://根据服务名从注册中心获取服务请求地址           predicates:                 # 断言             - Path=/product/**        # 匹配对应URL请求
  1. 修改启动类
@SpringBootApplication @EnableDiscoveryClient public class GatewayServerApplication {     public static void main(String[] args) {         SpringApplication.run(GatewayServerApplication.class, args);     } }
  1. 测试请求http://localhost:8892/product/1 将会路由至http://localhost:8890/product/1

自动生成基于服务发现的路由规则

# 应用名称 spring:   profiles: dynRoute   cloud:     gateway:       discovery:         # 是否与服务发现组件进行结合,通过serviceId转发到具体服务实例         locator:           enabled: true    #是否开启基于服务发现的路由规则           lower-case-service-id: true   #  是否将服务名称转换小写

开启自动生成服务发现路由规则,Spring Cloud Gateway将根据获取的服务列表自动生成路由规则,以服务标识来匹配具体的路由规则,测试如下:

  • 请求http://localhost:8892/product-service/product/1转发到 http://localhost:8890/product/1
  • 请求http://localhost:8892/product/1 404错误