Global filter介绍
Spring gateway 是网关系统一般先确定好Route,然后就会执行 global filter 和 gateway filter,global filter 的职责就是对整个的转发流程进行控制,gateway filter 只是对对请求过去的和返回的时候进行相应的修改。
The
ForwardRoutingFilter
looks for a URI in the exchange attributeServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR
. If the URL has aforward
scheme (such asforward:///localendpoint
), it uses the SpringDispatcherHandler
to handle the request. The path part of the request URL is overridden with the path in the forward URL. The unmodified original URL is appended to the list in theServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR
attribute.意思是这个filter首先会检查exchange attribute里面是否有
ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR,如果包含有forward的标记,会交给Spring的DispatcherHandler
去处理,部分的url会被forward url所覆盖,原来不可更改的 url会给列到ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR
attribute. 属性中
LoadBalancerClientFilter
The
LoadBalancerClientFilter
looks for a URI in the exchange attribute namedServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR
. If the URL has a scheme oflb
(such aslb://myservice
), it uses the Spring CloudLoadBalancerClient
to resolve the name (myservice
in this case) to an actual host and port and replaces the URI in the same attribute. The unmodified original URL is appended to the list in theServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR
attribute. The filter also looks in theServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR
attribute to see if it equalslb
. If so, the same rules apply. The following listing configures aLoadBalancerClientFilter
:这个filter会检查scheme是否有lb的前缀(就是loadbalace的缩写),如果有Spring cloud的 loadbalaceClient类会解析服务的名字,并且得到一个真正的host和端口,然后替换url.然后原来的url也会列在原来的
GATEWAY_ORIGINAL_REQUEST_URL_ATTR
属性中。
LoadBalancerClientFilter
uses a blocking ribbonLoadBalancerClient
under the hood. We suggest you use ReactiveLoadBalancerClientFilter. You can switch to it by setting the value of thespring.cloud.loadbalancer.ribbon.enabled
tofalse
官方建议你使用
ReactiveLoadBalancerClientFilter
,通过配置文件关闭spring.cloud.loadbalancer.ribbon.enabled
tofalse
ReactiveLoadBalancerClientFilter
he
ReactiveLoadBalancerClientFilter
looks for a URI in the exchange attribute namedServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR
. If the URL has alb
scheme (such aslb://myservice
), it uses the Spring CloudReactorLoadBalancer
to resolve the name (myservice
in this example) to an actual host and port and replaces the URI in the same attribute. The unmodified original URL is appended to the list in theServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR
attribute. The filter also looks in theServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR
attribute to see if it equalslb
. If so, the same rules apply. The following listing configures aReactiveLoadBalancerClientFilter
:这个loadbalace 其实reactive 实现的一种,非阻塞,是官方推荐使用的。
The Netty routing filter runs if the URL located in the
ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR
exchange attribute has ahttp
orhttps
scheme. It uses the NettyHttpClient
to make the downstream proxy request. The response is put in theServerWebExchangeUtils.CLIENT_RESPONSE_ATTR
exchange attribute for use in a later filter. (There is also an experimentalWebClientHttpRoutingFilter
that performs the same function but does not require Netty.)如果属性里面包含http 或者 https的scheme 它会使用的netty的httpclient去请求代理请求,然后返回的response会放到
CLIENT_RESPONSE_ATTR属性给后面的filter来使用
NettyWriteResponseFilter
The
NettyWriteResponseFilter
runs if there is a NettyHttpClientResponse
in theServerWebExchangeUtils.CLIENT_RESPONSE_ATTR
exchange attribute. It runs after all other filters have completed and writes the proxy response back to the gateway client response. (There is also an experimentalWebClientWriteResponseFilter
that performs the same function but does not require Netty.)这个filter会在拿到了response之后才会执行。
If there is a
Route
object in theServerWebExchangeUtils.GATEWAY_ROUTE_ATTR
exchange attribute, theRouteToRequestUrlFilter
runs. It creates a new URI, based off of the request URI but updated with the URI attribute of theRoute
object. The new URI is placed in theServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR
exchange attribute`.If the URI has a scheme prefix, such as
lb:ws://serviceid
, thelb
scheme is stripped from the URI and placed in theServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR
for use later in the filter chain如果Route 在
GATEWAY_ROUTE_ATTR
里面,这个filter就会执行,它会创建一个新的url,然后更新Route里面url地址。
GlobalFilter | Pre or Post filter | 执行条件 | 作用介绍 |
RemoveCachedBodyFilter | Post | key为 cachedRequestBody的value有内容 | 删除缓存中 key为: cachedRequestBody |
AdaptCachedBodyGlobalFilter | pre | RetryGatewayFilterFactory重试时,会在执行重试逻辑时发布EnableBodyCachingEvent | 增加缓存,避免retry的时候 重新触发流程 |
NettyWriteResponseFilter | post | 拿到了Repsonse connection 连接 | 把从代理中获取的数据写入到请求的连接中 |
ForwardPathFilter | pre | 配置了 forward 的url地址 | 重定向指定的url地址 |
GatewayMetricsFilter | post | | 收集监控数据的filter |
RouteToRequestUrlFilter | pre | Route对象已经存到 gatewayRoute 属性的值里面了 | 生产和组装成真正请求的url地址 |
LoadBalancerClientFilter | pre | 配置了 lb:serviceId && (http || https) | 负载均衡的filter |
WebsocketRoutingFilter | pre | 配置了 ws or wss | |
NettyRoutingFilter | pre |
|
根据Route对象信息去做真实的请求动作 |
ForwardRoutingFilter | pre | 能根据gatewayRequestUrl 拿到值 | 用来处理forward协议的请求,将 |
Global filter调用顺序
Gateway filter 执行顺序
1:gateway filter在调用前还是调用执行是通过代码 的业务逻辑靠代码写在 chain.filter 之前还是之后确定的,假如是之前就是 pre filter ,之后是 post filter
2: gateway filter 的默认是 PrefixPathGatewayFilterFactory
3: gateway filter的执行顺序是有定义来决定的,也可以靠@order来控制。
/**
* 在加载filter的时候进行filter 排序
* * @param id
* @param filterDefinitions
* @return
*/
@SuppressWarnings("unchecked")
List<GatewayFilter> loadGatewayFilters(String id,
List<FilterDefinition> filterDefinitions) {
ArrayList<GatewayFilter> ordered = new ArrayList<>(filterDefinitions.size());
for (int i = 0; i < filterDefinitions.size(); i++) {
FilterDefinition definition = filterDefinitions.get(i);
GatewayFilterFactory factory = this.gatewayFilterFactories
.get(definition.getName());
if (factory == null) {
throw new IllegalArgumentException(
"Unable to find GatewayFilterFactory with name "
+ definition.getName());
}
if (logger.isDebugEnabled()) {
logger.debug("RouteDefinition " + id + " applying filter "
+ definition.getArgs() + " to " + definition.getName());
}
// @formatter:off
Object configuration = this.configurationService.with(factory)
.name(definition.getName())
.properties(definition.getArgs())
.eventFunction((bound, properties) -> new FilterArgsEvent(
// TODO: why explicit cast needed or java compile fails
RouteDefinitionRouteLocator.this, id, (Map<String, Object>) properties))
.bind();
// @formatter:on
// some filters require routeId
// TODO: is there a better place to apply this?
if (configuration instanceof HasRouteId) {
HasRouteId hasRouteId = (HasRouteId) configuration;
hasRouteId.setRouteId(id);
}
GatewayFilter gatewayFilter = factory.apply(configuration);
if (gatewayFilter instanceof Ordered) {
ordered.add(gatewayFilter);
}
else {
//设置order编号
ordered.add(new OrderedGatewayFilter(gatewayFilter, i + 1));
}
}
return ordered;
}