环境:SpringBoot2.7.12 + SpringCloud2021.0.7
1. 简介
Spring Cloud Gateway 中,路由断言(predicates)和过滤器(filters)是两个核心概念,它们共同决定了如何处理进入网关的请求。
谓词工厂
谓词工厂用于定义路由断言。断言是路由的一个条件,只有当条件满足时,请求才会被路由到指定的服务。Spring Cloud Gateway 提供了一系列的内置断言,例如基于路径、请求头、请求方法等的断言。然而,如果你需要实现一些特定的业务逻辑或自定义条件,你可以创建自定义的谓词工厂。
自定义谓词工厂通常需要实现 org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory
或其子类,并定义断言的条件。在创建自定义谓词工厂时,你需要指定谓词的名字、配置类以及断言的匹配逻辑。
例如,你可以创建一个自定义谓词工厂来检查请求中是否包含特定的自定义请求头。
网关过滤器工厂
网关过滤器工厂用于定义在路由匹配后应用于请求的过滤器。这些过滤器可以对请求和响应进行修改,例如添加请求头、修改响应体或进行身份验证等。Spring Cloud Gateway 同样提供了一系列的内置过滤器,但同样,如果你需要实现特定的业务逻辑或自定义处理,你可以创建自定义的网关过滤器工厂。
自定义网关过滤器工厂通常需要实现 org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory
,并定义过滤器的逻辑。你可以在这里编写 Java 代码来实现对请求和响应的自定义处理。
例如,你可以创建一个自定义网关过滤器工厂来记录每个请求的详细信息,或者根据特定的业务逻辑修改响应的内容。
2. 实战案例
2.1 自定义谓词工厂
该谓词工厂的作用检查请求参数及header中个性化的信息。
@Component
public class ParamHeaderRoutePredicateFactory extends AbstractRoutePredicateFactory<ParamHeaderRoutePredicateFactory.Config> {
public static final String PARAM_KEY = "param";
public static final String HEADER_KEY = "header" ;
public static final String PARAM_VALUE = "pv" ;
public static final String HEADER_VALUE = "hv" ;
public ParamHeaderRoutePredicateFactory() {
super(Config.class);
}
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList(PARAM_KEY, PARAM_VALUE, HEADER_KEY, HEADER_VALUE) ;
}
@Override
public Predicate<ServerWebExchange> apply(Config config) {
return new GatewayPredicate() {
@Override
public boolean test(ServerWebExchange t) {
String pv = t.getRequest().getQueryParams().getFirst(config.param) ;
String hv = t.getRequest().getHeaders().getFirst(config.header) ;
System.err.printf("请求参数: %s=%s, 请求头: %s=%s%n", config.param, pv, config.header, hv) ;
return config.pv.equals(pv) && config.hv.equals(hv) ;
}
} ;
}
// 验证配置参数
@Validated
public static class Config {
@NotEmpty(message = "参数param不能为空")
private String param ;
@NotEmpty(message = "请求header不能为空")
private String header ;
private String pv ;
private String hv ;
// getter, setter
}
}
使用
spring:
cloud:
gateway:
default-filters:
- StripPrefix=1
routes:
- id: pack-lbs-1
uri: packlb://cloudAppServiceProvider
predicates:
#- ParamHeader=q,java,v,1
- name: ParamHeader
args:
param: q
pv: java
header: v
hv: 1
请求中的q参数值必须是java,请求header中的v值必须是1,才会匹配该路径。
2.2 自定义网关过滤器工厂
该过滤器的功能是改写请求参数信息。
@Component
public class CustomGatewayFilterFactory extends AbstractGatewayFilterFactory<Config> {
public CustomGatewayFilterFactory() {
super(Config.class) ;
}
@Override
public List<String> shortcutFieldOrder() {
return super.shortcutFieldOrder() ;
}
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
Route r = exchange.getAttribute(GATEWAY_ROUTE_ATTR) ;
Map<String,Object> metadata = r.getMetadata() ;
System.out.println(metadata) ;
ServerHttpRequest request = exchange.getRequest() ;
URI uri = request.getURI() ;
// 获取idNo参数,改写请求参数idNo数值
MultiValueMap<String, String> queryParams = request.getQueryParams();
String idNo = queryParams.getFirst("idNo") ;
// 对idNo参数进行解密操作(只是演示)
idNo = idNo + "-new" ;
// 这里为了演示简单,不考虑多个参数的情况
String query = "idNo=" + idNo ;
System.out.println(uri) ;
URI newUri = UriComponentsBuilder.fromUri(uri).replaceQuery(query).build(true).toUri() ;
System.out.println(newUri) ;
Builder builder = request.mutate().uri(newUri) ;
return chain.filter(exchange.mutate().request(builder.build()).build()) ;
};
}
public static class Config {
}
}
使用
spring:
cloud:
gateway:
routes:
- id: demo-service-01
uri: http://localhost:8088
predicates:
- name: Path
args:
a: /api-x/**
filters:
- name: Custom
测试
Spring Cloud Gateway 的自定义谓词工厂和网关过滤器工厂为开发者提供了灵活性和扩展性,使得开发者可以根据业务需求自定义路由条件和请求处理逻辑。通过实现这些自定义组件,你可以轻松地构建出满足特定业务需求的 API 网关。