过滤器(Filter)
GatewayFilter允许以某种方式修改传入的HTTP请求或传出的HTTP响应。路由过滤器的作用域是特定的路由。 Spring Cloud Gateway包括许多内置的GatewayFilter工厂。
GlobalFilter接口具有与GatewayFilter相同的签名。这些是特殊过滤器,有条件地应用于所有路由。
https://docs.spring.io/spring-cloud-gateway/docs/3.0.2/reference/html/#gatewayfilter-factories
这个文档中,有两种Filter(GatewayFilter和GlobalFilter)
GatewayFilter官网给出了这么31个过滤器工厂(工厂就是产生对象的,也就是相当于31个过滤器),
GlobalFilter官网给出了这么10个过滤器工厂(工厂就是产生对象的,也就是相当于10个过滤器):
生命周期
Spring Cloud Gateway同zuul类似,有“pre”和“post”两种方式的filter。客户端的请求先经过“pre”类型的filter,然后将请求转发到具体的业务服务,收到业务服务的响应之后,再经过“post”类型的filter处理,最后返回响应到客户端。
与zuul不同的是,filter除了分为“pre”和“post”两种方式的filter外,在Spring Cloud Gateway中,filter从作用范围可分为另外两种,一种是针对于单个路由的gateway filter,它在配置文件中的写法同predict类似;另外一种是针对于所有路由的global gateway filer。现在从作用范围划分的维度来讲解这两种filter。
gateway filter
过滤器允许以某种方式修改传入的HTTP请求或传出的HTTP响应。过滤器可以限定作用在某些特定请求路径上。 Spring Cloud Gateway包含许多内置的GatewayFilter工厂。
GatewayFilter工厂同上一篇介绍的Predicate工厂类似,都是在配置文件application.yml中配置,遵循了约定大于配置的思想,只需要在配置文件配置GatewayFilter Factory的名称,而不需要写全部的类名,比如AddRequestHeaderGatewayFilterFactory只需要在配置文件中写AddRequestHeader,而不是全部类名。在配置文件中配置的GatewayFilter Factory最终都会相应的过滤器工厂类处理。
Spring Cloud Gateway 内置的过滤器工厂一览表如下:
怎么用呢?
就像是断言(Predicate)一样,在spring.cloud.gateway.routes
下面添加就好了,和id
、uri
同级。
现在挑几个常见的过滤器工厂来讲解,每一个过滤器工厂在官方文档都给出了详细的使用案例,如果不清楚的还可以在org.springframework.cloud.gateway.filter.factory看每一个过滤器工厂的源码。
AddRequestHeader GatewayFilter Factory
server:
port: 9090
spring:
application:
name: @artifactId@
cloud:
nacos:
discovery:
server-addr: 172.17.169.81:8848
gateway:
discovery:
locator:
enabled: true # 开启从注册中心动态创建路由的功能,利用微服务名称j进行路由
routes:
- id: payment_route # 路由的id,没有规定规则但要求唯一,建议配合服务名
#匹配后提供服务的路由地址
#uri: http://localhost:8070/payment/get/31
uri: lb://payment-service
#uri: http://localhost:8070
predicates:
#- Path=/payment/get/** # 断言,路径相匹配的进行路由
- After=2021-01-20T17:42:47.789-07:00[America/Denver]
#- Before=2022-01-20T17:42:47.789-07:00[America/Denver]
#- Cookie=username,liu
#- Header=X-Request-Id, \d+ #请求头要有X-Request-Id属性,并且值为正数
#- Host=**.baidu.com
#- Method=GET
#- Query=username, \d+ # 要有参数名username并且值还要是正整数才能路由
# 过滤
filters:
- AddRequestHeader=X-Request-Foo, liu
#filters:
# - AddRequestHeader=X-Request-red, blue
#- id: payment_route2
# uri: http://localhost:8001
# predicates:
#Path=/payment/lb/** #断言,路径相匹配的进行路由
有一个filter为AddRequestHeaderGatewayFilterFactory(约定写成AddRequestHeader),AddRequestHeader过滤器工厂会在请求头加上一对请求头,名称为X-Request-Foo,值为liu。为了验证AddRequestHeaderGatewayFilterFactory是怎么样工作的,查看它的源码,AddRequestHeaderGatewayFilterFactory的源码如下:
public class AddRequestHeaderGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {
@Override
public GatewayFilter apply(NameValueConfig config) {
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest().mutate()
.header(config.getName(), config.getValue())
.build();
return chain.filter(exchange.mutate().request(request).build());
};
}
}
由上面的代码可知,根据旧的ServerHttpRequest创建新的 ServerHttpRequest ,在新的ServerHttpRequest加了一个请求头,然后创建新的 ServerWebExchange ,提交过滤器链继续过滤。
跟AddRequestHeader过滤器工厂类似的还有AddResponseHeader过滤器工厂,在此就不再重复。
RewritePath GatewayFilter Factory
在Nginx服务启中有一个非常强大的功能就是重写路径,Spring Cloud Gateway默认也提供了这样的功能,这个功能是Zuul没有的。在配置文件中加上以下的配置:
server:
port: 9090
spring:
application:
name: @artifactId@
cloud:
nacos:
discovery:
server-addr: 172.17.169.81:8848
gateway:
discovery:
locator:
enabled: true # 开启从注册中心动态创建路由的功能,利用微服务名称j进行路由
routes:
- id: payment_route # 路由的id,没有规定规则但要求唯一,建议配合服务名
#匹配后提供服务的路由地址
#uri: http://localhost:8070/payment/get/31
uri: lb://payment-service
#uri: http://localhost:8070
predicates:
#- Path=/payment/get/** # 断言,路径相匹配的进行路由
- After=2021-01-20T17:42:47.789-07:00[America/Denver]
#- Before=2022-01-20T17:42:47.789-07:00[America/Denver]
#- Cookie=username,liu
#- Header=X-Request-Id, \d+ #请求头要有X-Request-Id属性,并且值为正数
#- Host=**.baidu.com
#- Method=GET
#- Query=username, \d+ # 要有参数名username并且值还要是正整数才能路由
# 过滤
filters:
- RewritePath=/api/(?<segment>.*), /$\{segment}
#- AddRequestHeader=X-Request-red, blue
#- id: payment_route2
# uri: http://localhost:8001
# predicates:
#Path=/payment/lb/** #断言,路径相匹配的进行路由
上面的配置中,所有的/api/**开始的路径都会命中配置的router,并执行过滤器的逻辑,在本案例中配置了RewritePath过滤器工厂,此工厂将/api/(?.*)重写为{segment},然后转发。比如在网页上请求http://localhost:9090/api/payment/get/31,此时会将请求转发到http://localhost:8070的页面
平时我们最常用的是自定义过滤器,所以这里就不做详细描述,官方文档中有详细实现配置,有兴趣的小伙伴可以访问官网查看:
StripPrefix前缀网关过滤器工厂采用一个参数StripPrefix。
StripPrefix参数表示在将请求发送到下游之前从请求中剥离的路径个数。
spring: cloud: gateway: routes: - id: aaaaa-bbbb uri: lb://aaaaa-bbbb predicates: - Path=/aa/** filters: - StripPrefix=2
当通过网关向/name/bar/foo发出请求时,去除两层相当于对nameservice的请求将类似于lb://aaaaa-bbbb/foo。
网关的断言结合过滤器,实现路由调转,理解后很容易应用,总体上应用上很容易!
微服务部署图可以加深路由的理解
两讲讲解了断言及自带过滤器,但最常用的还是自定义过滤器,下面重点讲解自定义过滤器!