Global filter介绍 

Spring gateway 是网关系统一般先确定好Route,然后就会执行 global filter 和 gateway filter,global filter 的职责就是对整个的转发流程进行控制,gateway filter 只是对对请求过去的和返回的时候进行相应的修改。

 Forward Routing Filter 

The ForwardRoutingFilter looks for a URI in the exchange attribute ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR. If the URL has a forward scheme (such as forward:///localendpoint), it uses the Spring DispatcherHandler 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 the ServerWebExchangeUtils.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 named ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR. If the URL has a scheme of lb (such as lb://myservice), it uses the Spring Cloud LoadBalancerClient 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 the ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR attribute. The filter also looks in the ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR attribute to see if it equals lb. If so, the same rules apply. The following listing configures a LoadBalancerClientFilter

这个filter会检查scheme是否有lb的前缀(就是loadbalace的缩写),如果有Spring cloud的 loadbalaceClient类会解析服务的名字,并且得到一个真正的host和端口,然后替换url.然后原来的url也会列在原来的GATEWAY_ORIGINAL_REQUEST_URL_ATTR 属性中。

LoadBalancerClientFilter uses a blocking ribbon LoadBalancerClient under the hood. We suggest you use ReactiveLoadBalancerClientFilter. You can switch to it by setting the value of the spring.cloud.loadbalancer.ribbon.enabled to false

官方建议你使用 ReactiveLoadBalancerClientFilter ,通过配置文件关闭 spring.cloud.loadbalancer.ribbon.enabled to false

ReactiveLoadBalancerClientFilter

he ReactiveLoadBalancerClientFilter looks for a URI in the exchange attribute named ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR. If the URL has a lb scheme (such as lb://myservice), it uses the Spring Cloud ReactorLoadBalancer 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 the ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR attribute. The filter also looks in the ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR attribute to see if it equals lb. If so, the same rules apply. The following listing configures a ReactiveLoadBalancerClientFilter

这个loadbalace 其实reactive 实现的一种,非阻塞,是官方推荐使用的。

The Netty Routing Filter

The Netty routing filter runs if the URL located in the ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR exchange attribute has a http or https scheme. It uses the Netty HttpClient to make the downstream proxy request. The response is put in the ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR exchange attribute for use in a later filter. (There is also an experimental WebClientHttpRoutingFilter 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 Netty HttpClientResponse in the ServerWebExchangeUtils.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 experimental WebClientWriteResponseFilter that performs the same function but does not require Netty.) 

这个filter会在拿到了response之后才会执行。

The RouteToRequestUrl 

If there is a Route object in the ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR exchange attribute, the RouteToRequestUrlFilter runs. It creates a new URI, based off of the request URI but updated with the URI attribute of the Route object. The new URI is placed in the ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR exchange attribute`.

If the URI has a scheme prefix, such as lb:ws://serviceid, the lb scheme is stripped from the URI and placed in the ServerWebExchangeUtils.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

能根据gatewayRequestUrl属性拿到Route

 

根据Route对象信息去做真实的请求动作

ForwardRoutingFilter

pre

能根据gatewayRequestUrl 拿到值

用来处理forward协议的请求,将ForwardPathFilter构建的新的Request发送给DispatcherHandler处理

 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;
	}