在Spring-Cloud-Gateway之请求处理流程中最终网关是将请求交给过滤器链表进行处理。html
核心接口:GatewayFilter,GlobalFilter,GatewayFilterChain。spring
查看总体类图编程
当使用微服务构建整个 API 服务时,通常有许多不一样的应用在运行,如上图所示的mst-user-service
、mst-good-service
和mst-order-service
,这些服务都须要对客户端的请求的进行 Authentication。最简单粗暴的方法就是像上图同样,为每一个微服务应用都实现一套用于校验的过滤器或拦截器。安全
经过前置的网关服务来完成这些非业务性质的校验。app
Spring Cloud Gateway 的 Filter 的生命周期有两个:“pre” 和 “post”。负载均衡
“pre”和 “post” 分别会在请求被执行前调用和被执行后调用,和 Zuul Filter 或 Spring Interceptor 中相关生命周期相似,但在形式上有些不同。ide
Zuul 的 Filter 是经过filterType()
方法来指定,一个 Filter 只能对应一种类型,要么是 “pre” 要么是“post”。Spring Interceptor 是经过重写HandlerInterceptor
中的三个方法来实现的。而 Spring Cloud Gateway 基于 Project Reactor 和 WebFlux,采用响应式编程风格,打开它的 Filter 的接口GatewayFilter
你会发现它只有一个方法filter
。函数
/** * 网关过滤链表接口 * 用于过滤器的链式调用 */ public interface GatewayFilterChain { /** * 链表启动调用入口方法*/ Mono<Void> filter(ServerWebExchange exchange); }
默认实现微服务
/** * 网关过滤的链表,用于过滤器的链式调用 * 过滤器链表接口的默认实现, * 包含2个构建函数: * 1.集合参数构建用于初始化吧构建链表 * 2. index,parent参数用于构建当前执行过滤对应的下次执行的链表 */ private static class DefaultGatewayFilterChain implements GatewayFilterChain { /** * 当前过滤执行过滤器在集合中索引 */ private final int index; /** * 过滤器集合 */ private final List<GatewayFilter> filters; public DefaultGatewayFilterChain(List<GatewayFilter> filters) { this.filters = filters; this.index = 0; } /** * 构建 * @param parent 上一个执行过滤器对应的FilterChain * @param index 当前要执行过滤器的索引 */ private DefaultGatewayFilterChain(DefaultGatewayFilterChain parent, int index) { this.filters = parent.getFilters(); this.index = index; } public List<GatewayFilter> getFilters() { return filters; } /** * @param exchange the current server exchange * @return */ @Override public Mono<Void> filter(ServerWebExchange exchange) { return Mono.defer(() -> { if (this.index < filters.size()) { //获取当前索引的过滤器 GatewayFilter filter = filters.get(this.index); //构建当前索引的下一个过滤器的FilterChain DefaultGatewayFilterChain chain = new DefaultGatewayFilterChain(this, this.index + 1); //调用过滤器的filter方法执行过滤器 return filter.filter(exchange, chain); } else { //当前索引大于等于过滤集合大小,标识全部链表都已执行完毕,返回空 return Mono.empty(); // complete } }); } }
过滤器的GatewayFilterChain 执行顺序post
/** * 网关路由过滤器, * Contract for interception-style, chained processing of Web requests that may * be used to implement cross-cutting, application-agnostic requirements such * as security, timeouts, and others. Specific to a Gateway * */ public interface GatewayFilter extends ShortcutConfigurable { String NAME_KEY = "name"; String VALUE_KEY = "value"; /** * 过滤器执行方法 * Process the Web request and (optionally) delegate to the next * {@code WebFilter} through the given {@link GatewayFilterChain}. * @param exchange the current server exchange * @param chain provides a way to delegate to the next filter * @return {@code Mono<Void>} to indicate when request processing is complete */ Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain); }
网关过滤器接口,有且只有一个方法filter,执行当前过滤器,并在此方法中决定过滤器链表是否继续往下执行。
1️⃣、OrderedGatewayFilter--排序
/** * 排序的网关路由过滤器,用于包装真实的网关过滤器,已达到过滤器可排序 */ public class OrderedGatewayFilter implements GatewayFilter, Ordered { //目标过滤器 private final GatewayFilter delegate; //排序字段 private final int order; public OrderedGatewayFilter(GatewayFilter delegate, int order) { this.delegate = delegate; this.order = order; } @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { return this.delegate.filter(exchange, chain); } }
OrderedGatewayFilter实现类主要目的是为了将目标过滤器包装成可排序的对象类型。是目标过滤器的包装类
2️⃣、GatewayFilterAdapter
/** * 全局过滤器的包装类,将全局路由包装成统一的网关过滤器 */ private static class GatewayFilterAdapter implements GatewayFilter { /** * 全局过滤器 */ private final GlobalFilter delegate; public GatewayFilterAdapter(GlobalFilter delegate) { this.delegate = delegate; } @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { return this.delegate.filter(exchange, chain); } }
GatewayFilterAdapter实现类主要目的是为了将GlobalFilter过滤器包装成GatewayFilter类型的对应。是GlobalFilter过滤器的包装类
GlobalFilter 为请求业务以及路由的URI转换为真实业务服务的请求地址的核心过滤器,不须要配置,模式系统初始化时加载,并做用在每一个路由上。
1️⃣、初始化加载,经过GatewayAutoConfiguration自动建立
//GatewayAutoConfiguration 类 /** * 全局过滤器,用户经过HttpClient转发请求 */ @Bean public NettyRoutingFilter routingFilter(HttpClient httpClient, ObjectProvider<List<HttpHeadersFilter>> headersFilters) { return new NettyRoutingFilter(httpClient, headersFilters); } /** * 全局的过滤器,用户将HttpClient客户端转发请求的响应写入到原始的请求响应中 */ @Bean public NettyWriteResponseFilter nettyWriteResponseFilter(GatewayProperties properties) { return new NettyWriteResponseFilter(properties.getStreamingMediaTypes()); } //GatewayLoadBalancerClientAutoConfiguration 类 /** * 全局过滤器,用于在经过负载均衡客户端选择服务实例信息 */ @Bean @ConditionalOnBean(LoadBalancerClient.class) public LoadBalancerClientFilter loadBalancerClientFilter(LoadBalancerClient client) { return new LoadBalancerClientFilter(client); }
2️⃣、GlobalFilter转换成GatewayFilter,并做用于每一个路由上,在FilteringWebHandler实现
//FilteringWebHandler类 /** * 包装加载全局的过滤器,将全局过滤器包装成GatewayFilter */ private static List<GatewayFilter> loadFilters(List<GlobalFilter> filters) { return filters.stream() .map(filter -> { //将全部的全局过滤器包装成网关过滤器 GatewayFilterAdapter gatewayFilter = new GatewayFilterAdapter(filter); //判断全局过滤器是否实现了可排序接口 if (filter instanceof Ordered) { int order = ((Ordered) filter).getOrder(); //包装成可排序的网关过滤器 return new OrderedGatewayFilter(gatewayFilter, order); } return gatewayFilter; }).collect(Collectors.toList()); } @Override public Mono<Void> handle(ServerWebExchange exchange) { //获取请求上下文设置的路由实例 Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR); //获取路由定义下的网关过滤器集合 List<GatewayFilter> gatewayFilters = route.getFilters(); //组合全局的过滤器与路由配置的过滤器 List<GatewayFilter> combined = new ArrayList<>(this.globalFilters); //添加路由配置过滤器到集合尾部 combined.addAll(gatewayFilters); //对过滤器进行排序 //TODO: needed or cached? AnnotationAwareOrderComparator.sort(combined); logger.debug("Sorted gatewayFilterFactories: "+ combined); //建立过滤器链表对其进行链式调用 return new DefaultGatewayFilterChain(combined).filter(exchange); }
Spring-Cloud-Gateway的过滤器接口分为两种:
1️⃣、加载GatewayFilter
在路由定位器中以及看到了经过路由定义转换路由方法,其中包含了经过过滤器定义(FilterDefinition)转换过滤器(GatewayFilter)的部分,在RouteDefinitionRouteLocator类中源码以下:
/** * 加载过滤器,根据过滤器的定义加载 */ @SuppressWarnings("unchecked") private List<GatewayFilter> loadGatewayFilters(String id, List<FilterDefinition> filterDefinitions) { //遍历过滤器定义,将过滤器定义转换成对应的过滤器 List<GatewayFilter> filters = filterDefinitions.stream() .map(definition -> { //经过过滤器定义名称获取过滤器建立工厂 GatewayFilterFactory factory = this.gatewayFilterFactories.get(definition.getName()); if (factory == null) { throw new IllegalArgumentException("Unable to find GatewayFilterFactory with name " + definition.getName()); } //获取参数 Map<String, String> args = definition.getArgs(); if (logger.isDebugEnabled()) { logger.debug("RouteDefinition " + id + " applying filter " + args + " to " + definition.getName()); } //根据args组装配置信息 Map<String, Object> properties = factory.shortcutType().normalize(args, factory, this.parser, this.beanFactory); //构建过滤器建立配置信息 Object configuration = factory.newConfig(); ConfigurationUtils.bind(configuration, properties, factory.shortcutFieldPrefix(), definition.getName(), validator); //经过过滤器工厂建立GatewayFilter GatewayFilter gatewayFilter = factory.apply(configuration); if (this.publisher != null) { //发布事件 this.publisher.publishEvent(new FilterArgsEvent(this, id, properties)); } return gatewayFilter; }) .collect(Collectors.toList()); ArrayList<GatewayFilter> ordered = new ArrayList<>(filters.size()); //包装过滤器使其全部过滤器继承Ordered属性,可进行排序 for (int i = 0; i < filters.size(); i++) { GatewayFilter gatewayFilter = filters.get(i); if (gatewayFilter instanceof Ordered) { ordered.add(gatewayFilter); } else { ordered.add(new OrderedGatewayFilter(gatewayFilter, i + 1)); } } return ordered; } /** * 获取RouteDefinition中的过滤器集合 */ private List<GatewayFilter> getFilters(RouteDefinition routeDefinition) { List<GatewayFilter> filters = new ArrayList<>(); //校验gatewayProperties是否含义默认的过滤器集合 //TODO: support option to apply defaults after route specific filters? if (!this.gatewayProperties.getDefaultFilters().isEmpty()) { //加载全局配置的默认过滤器集合 filters.addAll(loadGatewayFilters("defaultFilters", this.gatewayProperties.getDefaultFilters())); } if (!routeDefinition.getFilters().isEmpty()) { //加载路由定义中的过滤器集合 filters.addAll(loadGatewayFilters(routeDefinition.getId(), routeDefinition.getFilters())); } //排序 AnnotationAwareOrderComparator.sort(filters); return filters; }
子类及其划分
3️⃣、AddResponseHeaderGatewayFilterFactory 建立解析
/** * * 响应header添加数据过滤器 * 用户在response header中添加配置数据 */ public class AddResponseHeaderGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory { @Override public GatewayFilter apply(NameValueConfig config) { return (exchange, chain) -> { //获取Response并将配置的数据添加到header中 exchange.getResponse().getHeaders().add(config.getName(), config.getValue()); return chain.filter(exchange); }; } }。
配置示例:
spring: cloud: gateway: default-filters: - AddResponseHeader=X-Response-Default-Foo, Default-Bar
4️⃣、所有配置
5.一、请求头
spring:
cloud:
gateway:
routes:
- id: add_request_header_route uri: http://example.org filters: - AddRequestHeader=X-Request-Foo, Bar
名称和值,这将为全部匹配请求的下游请求标头添加X-Request-Foo:Bar标头。
移除请求头
filters:
- RemoveRequestHeader=X-Request-Foo
5.二、请求参数
filters:
- AddRequestParameter=foo, bar
这会将foo = bar添加到下游请求的全部匹配请求的查询字符串中。
5.三、添加响应头
filters:
- AddResponseHeader=X-Response-Foo, Bar
这会将X-Response-Foo:Bar标头添加到全部匹配请求的下游响应标头中。
移除响应头
filters:
- RemoveResponseHeader=X-Response-Foo
设置响应头
filters:
- SetResponseHeader=X-Response-Foo, Bar
此GatewayFilter将替换具备给定名称的全部标头,而不是添加。
5.四、路径前缀
filters:
- PrefixPath=/mypath
这将使/ mypath前缀为全部匹配请求的路径。因此对/ hello的请求会被发送到/ mypath / hello。
5.五、原始主机头
没有参数,此过滤器设置路由过滤器将检查的请求属性,以肯定是否应发送原始主机头,而不是http客户端肯定的主机头。
filters:
- PreserveHostHeader
5.六、重定向
filters:
- RedirectTo=302, http://acme.org
这将发送带有Location:http://acme.org标头的状态302以执行重定向。
5.七、重写路径
predicates:
- Path=/foo/**
filters:
- RewritePath=/foo/(?<segment>.*), /$\{segment}
对于/ foo / bar的请求路径,这将在发出下游请求以前将路径设置为/ bar。注意因为YAML规范,$ \替换为$。
5.八、保存Session
predicates:
- Path=/foo/**
filters:
- SaveSession
5.九、路径模板
SetPath GatewayFilter Factory采用路径模板参数。它提供了一种经过容许模板化路径段来操做请求路径的简单方法。
predicates:
- Path=/foo/{segment} filters: - SetPath=/{segment}
对于/ foo / bar的请求路径,这将在发出下游请求以前将路径设置为/ bar。
5.十、设置响应状态
spring:
cloud:
gateway:
routes:
- id: setstatusstring_route uri: http://example.org filters: - SetStatus=BAD_REQUEST - id: setstatusint_route uri: http://example.org filters: - SetStatus=401
5.十一、请求参数剥离
parts参数指示在将请求发送到下游以前从请求中剥离的路径中的部分数。
predicates:
- Path=/name/**
filters:
- StripPrefix=2
当经过网关向/ name / bar / foo发出请求时,对nameservice的请求将相似于http:// nameservice / foo。
5.十二、重试
retries:重试:应该尝试的重试次数
statuses:状态:应该重试的HTTP状态代码,使用org.springframework.http.HttpStatus表示
methods:方法:应该重试的HTTP方法,使用org.springframework.http.HttpMethod表示
series:系列:要重试的状态代码系列,使用org.springframework.http.HttpStatus.Series表示
routes:
- id: retry_test uri: http://localhost:8080/flakey predicates: - Host=*.retry.com filters: - name: Retry args: retries: 3 statuses: BAD_GATEWAY
5.1三、Hystrix GatewayFilter Factory
5.1四、请求限速
RequestRateLimiter GatewayFilter Factory
5.1五、安全头