欢迎光临
我们一直在努力

Spring Cloud Gateway 核心实战:断言(Predicate)的长短写法与自定义工厂详解

一、 断言(Predicate)是什么?

在 Spring Cloud Gateway 中,断言是路由规则的一部分。它是一个 Java 8 的 Predicate,接收一个 ServerWebExchange对象作为输入,返回一个布尔值。如果返回 true,则表示该请求匹配当前路由,网关会将请求转发到指定的 URI;否则,继续匹配下一个路由。

二、 断言的两种写法:短写法 vs 长写法

在配置文件(如 application.yml)中,断言有两种配置方式,它们的功能完全一致,只是写法不同。

1. 短写法(Shortcut Configuration)

这是最常用的写法,简洁明了。格式为:断言名称=参数1, 参数2, …。

  • 示例分析:

    predicates:
    – Path=/api/order/**
    – Path=/api/product/**

    • 这里的 Path是断言名称。

    • /api/order/**是参数,表示匹配以 /api/order/开头的所有路径。

2. 长写法(Full Configuration)

这种写法更显式,结构更清晰,适合复杂的断言配置。格式为:name: 断言名称, args: {参数名: 参数值}。

  • 示例分析:

    predicates:
    – name: Path
    args:
    patterns: /api/order/**
    matchTrailingSlash: true

    • name指定了断言类型。

    • args是一个 Map,包含了该断言所需的所有参数。例如 Path断言除了路径模式 patterns,还可以配置 matchTrailingSlash(是否匹配尾部斜杠)。

三、 Query 断言详解:如何根据查询参数路由?

Query断言用于匹配 HTTP 请求中的查询参数(Query Parameters)。这是实现灰度发布、A/B 测试或特定功能开关的利器。

1. 基础用法:匹配特定参数值

假设我们有一个搜索接口,只有当用户携带了特定的搜索关键词时,才允许访问。

  • 配置示例:

    predicates:
    – name: Query
    args:
    param: q
    regexp: haha

    • 含义:​ 匹配请求中包含 q参数,且其值必须符合正则表达式 haha的请求。

    • 场景:​ 例如 https://example.com/search?q=haha会被匹配,而 https://example.com/search?q=hello则不会。

2. 进阶用法:仅检查参数是否存在

有时候我们只需要检查某个参数是否存在,而不关心它的具体值。

  • 配置示例:

    predicates:
    – Query=q

    • 含义:​ 只要请求 URL 中包含 q参数(无论值是多少),都会匹配。例如 ?q=123或 ?q=都会匹配。

3. 组合使用:Path + Query

通常我们会将 Path和 Query组合使用,实现更精确的路由控制。

  • 配置示例:

    predicates:
    – Path=/api/search
    – Query=q, haha

    • 含义:​ 只有当请求路径是 /api/search且​ 查询参数 q的值为 haha时,才会触发该路由。

四、 自定义断言工厂:VipRoutePredicateFactory

虽然 Gateway 内置了丰富的断言(如 Path, Query, Header, Cookie 等),但业务需求千变万化。当内置断言无法满足需求时,我们需要自定义断言。

1. 需求场景

假设我们需要实现一个“VIP 通道”,只有当请求中携带了特定的 vipCode参数且值为 123456时,才允许访问某个高优先级的服务。

2. 代码实现

我们需要继承 AbstractRoutePredicateFactory并实现 apply方法。

package com.qcby.gateway.predicate;

import jakarta.validation.constraints.NotEmpty;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.GatewayPredicate;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.server.ServerWebExchange;

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

@Component
public class VipRoutePredicateFactory extends AbstractRoutePredicateFactory<VipRoutePredicateFactory.Config> {

// 1. 构造函数:指定配置类
public VipRoutePredicateFactory() {
super(Config.class);
}

// 2. 定义短写法的参数顺序
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList("param", "value");
}

// 3. 核心逻辑:定义匹配规则
@Override
public Predicate<ServerWebExchange> apply(Config config) {
return new GatewayPredicate() {
@Override
public boolean test(ServerWebExchange serverWebExchange) {
ServerHttpRequest request = serverWebExchange.getRequest();
// 获取请求中的查询参数
String paramValue = request.getQueryParams().getFirst(config.getParam());
// 判断参数是否存在且值是否匹配
if (StringUtils.hasText(paramValue) && paramValue.equals(config.getValue())) {
return true;
}
return false;
}
};
}

// 4. 配置类:定义断言所需的参数
@Validated
public static class Config {
@NotEmpty
private String param; // 参数名,如 vipCode

@NotEmpty
private String value; // 参数值,如 123456

// Getter & Setter
public String getParam() { return param; }
public void setParam(String param) { this.param = param; }
public String getValue() { return value; }
public void setValue(String value) { this.value = value; }
}
}

自定义断言工厂名字一定要在去掉RoutePredicateFactory之后和配置文件中的名字匹配

3. 配置使用

编写完代码后,重启网关服务,即可在配置文件中使用这个自定义断言。

spring:
cloud:
gateway:
routes:
– id: vip-route
uri: lb://vip-service
predicates:
– Vip=vipCode, 123456

  • 含义:​ 只有当请求中包含 vipCode=123456时,请求才会被转发到 vip-service。

五、 总结

Spring Cloud Gateway 的断言机制非常灵活且强大。通过掌握 Path、Query等内置断言的长短写法,我们可以轻松实现复杂的路由逻辑。而通过继承 AbstractRoutePredicateFactory编写自定义断言,我们可以将业务逻辑下沉到网关层,实现更精细化的流量控制。

赞(0)
未经允许不得转载:171主机测评 » Spring Cloud Gateway 核心实战:断言(Predicate)的长短写法与自定义工厂详解
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址