Gateway Header 路由断言工厂

Header 信息路由断言工厂需要两个参数,即 header 信息和 regexp(Java 正则表达式)。语法如下:

Header=请求头名称, 请求头的值

该断言与具有给定名称且其值符合正则表达式的header 匹配。例如:

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

上面配置,如果 HTTP 请求的 header 名为 X-Request-Id,并且其值符合 \d+ 正则表达式(即其值为一位或多位数字),则该路由与之匹配。

示例

将“Gateway 搭建网关服务”项目的配置文件 bootstrap.yml 内容使用如下配置替换:

server:
  # 网关端口
  port: 9000

spring:
  application:
    # 服务名称
    name: gateway-demo01
  cloud:
    # nacos
    nacos:
      discovery:
        server-addr: localhost:8848
        username: nacos
        password: nacos
        group: DEFAULT_GROUP

    # 网关路由配置
    gateway:
      # 网关路由配置
      routes:
        # 路由id,自定义,只要唯一集合
        - id: service-order
          # 路由的目标地址,lb 就是负载均衡,后面跟服务名
          # 需要集成 nacos 等服务注册中心
          uri: lb://service-order
          # 路由断言,也就是判断请求是否符合路由规则的条件
          predicates:
            # Header断言:匹配拥有名为 my_header,值为数字的请求头的请求
            - Header=my_header, \d+

修改好配置后,重启网关服务,使用 Postman 访问订单服务。注意,在访问服务时添加 my_header 头信息,如下图:

Gateway Header 路由断言工厂

上图可知,成功访问到订单接口。如果我们将请求头的值追加一个字符串(因此不满足 \d+ 正则表达式),请求将会失败,如下图:

Gateway Header 路由断言工厂

源码分析

下面是 Header 路由断言工厂源码:

package org.springframework.cloud.gateway.handler.predicate;

//...

public class HeaderRoutePredicateFactory extends AbstractRoutePredicateFactory<HeaderRoutePredicateFactory.Config> {

    public static final String HEADER_KEY = "header";
    public static final String REGEXP_KEY = "regexp";

    public HeaderRoutePredicateFactory() {
       super(Config.class);
    }

    @Override
    public List<String> shortcutFieldOrder() {
       return Arrays.asList(HEADER_KEY, REGEXP_KEY);
    }

    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
       boolean hasRegex = !StringUtils.isEmpty(config.regexp);

       return exchange -> {
          // 获取指定请求头所有的值
          List<String> values = exchange.getRequest().getHeaders().getOrDefault(config.header, Collections.emptyList());
          if (values.isEmpty()) {
             // 如果为空,则返回 false
             return false;
          }
          
          // 如果指定的正则表达式不为空
          // values is now guaranteed to not be empty
          if (hasRegex) {
             // 使用 JDK8 流操作,匹配请求头的值列表,匹配任何一个,则返回 true
             // check if a header value matches
             return values.stream().anyMatch(value -> value.matches(config.regexp));
          }

          // there is a value and since regexp is empty, we only check existence.
          return true;
       };
    }

    @Validated
    public static class Config {
       // HTTP 请求头名称
       @NotEmpty
       private String header;
       // 请求头字段值匹配的正则表达式
       private String regexp;

       // 配置信息
    }
}
说说我的看法
全部评论(
没有评论
关于
本网站属于个人的非赢利性网站,转载的文章遵循原作者的版权声明,如果原文没有版权声明,请来信告知:hxstrive@outlook.com
公众号