一、概念:
在微服务架构下,每个微服务都有不同的IP地址和端口,前端在访问时就需要针对每个微服务单独访问,一旦新增或者调整微服务后,前端也需要做同步的修改,非常麻烦,而且为了校验访问请求是合法的,每个微服务都需要都需要做安全校验。引入API网关后,前端就只需要访问API网关就行了,里面的请求转发和一些其他的验权都可以放在API网关里面进行统一处理。因此API网关的职责一是路由功能,根据定义的请求规则和转化的规则,将传入的请求映射到不同的微服务进行处理,另一个职责就是针对请求信息在API网关进行统一验权。SpringCloud Gateway是一款非常优秀性能强劲的API网关。
SpringCloud Gateway接收请求的总入口是DispatcherHandler,有两个非常重要的核心概念,就是路由(Route)和过滤器(Filter)。
1、路由(Route):Route 是网关的基础元素,由 ID、目标 URI、断言、过滤器组成。当请求到达网关时,由 Gateway HandlerMapping 通过断言进行路由匹配(Mapping),当断言为真时,匹配到路由。
Route的定义如下:
arduino
public class Route implements Ordered {
private final String id;
private final URI uri;
private final int order;
private final AsyncPredicate<ServerWebExchange> predicate;
private final List<GatewayFilter> gatewayFilters;
private final Map<String, Object> metadata;
...........
}
在配置文件定义的Route信息在SpringCloud Gateway里面叫做RouteDefinition,其定义如下:
typescript
public class RouteDefinition {
private String id;
private List<PredicateDefinition> predicates = new ArrayList<>();
private List<FilterDefinition> filters = new ArrayList<>();
private URI uri;
private Map<String, Object> metadata = new HashMap<>();
private int order = 0;
...........
}
public class PredicateDefinition {
private String name;
private Map<String, String> args = new LinkedHashMap<>();
............
}
public class FilterDefinition {
private String name;
private Map<String, String> args = new LinkedHashMap<>();
................
}
2、过滤器:过滤器可以在请求到达业务代码之前执行一些业务上的处理。SpringCloud gateway中有两种过滤器,路由过滤器(接口为GatewayFilter)和全局过滤器(接口为GlobalFilter);
路由过滤器GatewayFilter的定义如下:
kotlin
public interface GatewayFilter {
/**
* 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);
}
全局过滤器GlobalFilter的定义如下:
kotlin
public interface GlobalFilter {
/**
* 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);
}
二、使用Demo:
1、引入依赖:
xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
//由于采用了基于注册中心的动态路由,而注册中心使用的是eureka,因此需要引入eureka的包
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2、配置文件application.yml:
yaml
spring:
cloud:
gateway:
discovery:
locator:
enabled: true
lowerCaseServiceId: true
routes:
#netty 路由过滤器,http或https开头
- id: app1-route
uri: http://www.baidu.com
predicates:
- Path=/app1/**
filters:
#转发请求时去掉1级前缀
- StripPrefix=1
3、实现Filter:
kotlin
@Configuration
public class AccessFilter implements GlobalFilter, Ordered {
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//鉴权
Mono<Void> check = checkAccess(exchange);
return check != null ? check : chain.filter(exchange);
}
三、总流程:
首先来看一张官网上的SpringCloud Gateway的架构图:
1、客户端发送请求到Spring Cloud Gateway,也就是DispatcherHandler接收了请求,如果Gateway Handler Mapping 判定 这个请求和路由是匹配的,则这个请求会被发送到Gateway Web Handler。
2、Gateway Web Handler通过与该请求匹配的过滤器链执行该请求。
再具体点的流程图:
SpringCloud Gateway API网关的流程:
1、加载路由定义RouteDefinition的集合;
2、将RouteDefinition集合转换为Route实例集合;
3、DispatcherHandler根据URL请求匹配Route;
4、交由WebHandler(FilteringWebHandler)执行过滤器链;
5、执行业务代码,并处理返回结果数据;
下面将分别针对这个流程步骤进行解析。
四、加载路由定义RouteDefinition的集合:
RouteDefinition加载的接口是RouteDefinitionLocator,这个接口有多个实现,最常见的RouteDefinition分别是application.yml定义和从配置中心加载。
RouteDefinition接口的定义只有只有一个方法getRouteDefinitions,代码如下:
csharp
public interface RouteDefinitionLocator {
Flux<RouteDefinition> getRouteDefinitions();
}
1、application.yml定义的路由信息加载RouteDefinition:
比如上面的demo,就是在配置文件application.yml中定义路由信息的,其加载是由PropertiesRouteDefinitionLocator完成的。代码如下:
kotlin
public class PropertiesRouteDefinitionLocator implements RouteDefinitionLocator {
private final GatewayProperties properties;
public PropertiesRouteDefinitionLocator(GatewayProperties properties) {
this.properties = properties;
}
@Override
public Flux<RouteDefinition> getRouteDefinitions() {
return Flux.fromIterable(this.properties.getRoutes());
}
}
@ConfigurationProperties("spring.cloud.gateway")
public class GatewayProperties {
private List<RouteDefinition> routes = new ArrayList<>();
................
}
由GatewayProperties类可以看到SpringBoot启动时会将application.yml中定义的spring.cloud.gateway.routes下面的所有的信息都加载到routes中,PropertiesRouteDefinitionLocator直接引用GatewayProperties就可以读取到application.yml中定义的RouteDefinition。
2、从配置中心加载RouteDefinition:
从配置中心加载RouteDefinition是由DiscoveryClientRouteDefinitionLocator完成的。其定义和加载代码如下:
ini
public class DiscoveryClientRouteDefinitionLocator implements RouteDefinitionLocator {
//管理以spring.cloud.gateway.discovery.locator开头的属性定义
private final DiscoveryLocatorProperties properties;
private final String routeIdPrefix;
//存储注册中心的所有服务实例
private Flux<List<ServiceInstance>> serviceInstances;
public DiscoveryClientRouteDefinitionLocator(ReactiveDiscoveryClient discoveryClient, DiscoveryLocatorProperties properties) {
this(discoveryClient.getClass().getSimpleName(), properties);
//通过discoveryClient.getServices和discoveryClient.getInstances获取配置中心中的所有服务实例
serviceInstances = discoveryClient.getServices().flatMap(service -> discoveryClient.getInstances(service).collectList());
}
public Flux<RouteDefinition> getRouteDefinitions() {
.........省略部分代码............
return serviceInstances.filter(instances -> !instances.isEmpty())
.map(instance -> {
//从注册中心的服务实例信息构造RouteDefinition
RouteDefinition routeDefinition = buildRouteDefinition(urlExpr, instance);
//构造RouteDefinition的断言信息
for (PredicateDefinition original : this.properties.getPredicates()) {
PredicateDefinition predicate = new PredicateDefinition();
predicate.setName(original.getName());
for (Map.Entry<String, String> entry : original.getArgs().entrySet()) {
String value = getValueFromExpr(evalCtxt, parser, instanceForEval, entry);
predicate.addArg(entry.getKey(), value);
}
routeDefinition.getPredicates().add(predicate);
}
//构造RouteDefinition的过滤器链信息
for (FilterDefinition original : this.properties.getFilters()) {
FilterDefinition filter = new FilterDefinition();
filter.setName(original.getName());
for (Map.Entry<String, String> entry : original.getArgs()
.entrySet()) {
String value = getValueFromExpr(evalCtxt, parser,
instanceForEval, entry);
filter.addArg(entry.getKey(), value);
}
routeDefinition.getFilters().add(filter);
}
return routeDefinition;
});
}
protected RouteDefinition buildRouteDefinition(Expression urlExpr, ServiceInstance serviceInstance) {
String serviceId = serviceInstance.getServiceId();
RouteDefinition routeDefinition = new RouteDefinition();
routeDefinition.setId(this.routeIdPrefix + serviceId);
String uri = urlExpr.getValue(this.evalCtxt, serviceInstance, String.class);
routeDefinition.setUri(URI.create(uri));
// add instance metadata
routeDefinition.setMetadata(new LinkedHashMap<>(serviceInstance.getMetadata()));
return routeDefinition;
}
}
@ConfigurationProperties("spring.cloud.gateway.discovery.locator")
public class DiscoveryLocatorProperties {
private boolean enabled = false;
private String routeIdPrefix;
private String includeExpression = "true";
private String urlExpression = "'lb://'+serviceId";
private boolean lowerCaseServiceId = false;
private List<PredicateDefinition> predicates = new ArrayList<>();
private List<FilterDefinition> filters = new ArrayList<>();
................
}
1、DiscoveryClientRouteDefinitionLocator的构造函数中,会调用discoveryClient.getServices和discoveryClient.getInstances获取配置中心中的所有服务实例信息保存到serviceInstances中;
2、遍历serviceInstances,buildRouteDefinition依据每一个ServiceInstance构造一个RouteDefinition对象,predicates和filters信息则从DiscoveryLocatorProperties中读取,而DiscoveryLocatorProperties对于predicates和filters集合则只有定义而没有赋值,是不是很好奇他是怎么生成的,看看GatewayDiscoveryClientAutoConfiguration的中的配置就恍然大悟了:
less
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true)
@AutoConfigureBefore(GatewayAutoConfiguration.class)
@AutoConfigureAfter(CompositeDiscoveryClientAutoConfiguration.class)
@ConditionalOnClass({ DispatcherHandler.class })
@EnableConfigurationProperties
public class GatewayDiscoveryClientAutoConfiguration {
...........省略部分代码.........
@Bean
public DiscoveryLocatorProperties discoveryLocatorProperties() {
DiscoveryLocatorProperties properties = new DiscoveryLocatorProperties();
properties.setPredicates(initPredicates());
properties.setFilters(initFilters());
return properties;
}
public static List<PredicateDefinition> initPredicates() {
ArrayList<PredicateDefinition> definitions = new ArrayList<>();
PredicateDefinition predicate = new PredicateDefinition();
predicate.setName(normalizeRoutePredicateName(PathRoutePredicateFactory.class));
predicate.addArg("pattern", "'/'+serviceId+'/**'");
definitions.add(predicate);
return definitions;
}
public static List<FilterDefinition> initFilters() {
ArrayList<FilterDefinition> definitions = new ArrayList<>();
FilterDefinition filter = new FilterDefinition();
filter.setName(normalizeFilterFactoryName(RewritePathGatewayFilterFactory.class));
String regex = "'/' + serviceId + '/(?<remaining>.*)'";
String replacement = "'/${remaining}'";
filter.addArg("regexp", regex);
filter.addArg("replacement", replacement);
definitions.add(filter);
return definitions;
}
}
五、将RouteDefinition集合转换为Route实例集合:
RouteLocator接口用于将RouteDefinition转换为Route实例,这个接口只定义了一个方法getRoutes,代码如下:
csharp
public interface RouteLocator {
Flux<Route> getRoutes();
}
这个接口有三个实现类:CachingRouteLocator,CompositeRouteLocator,RouteDefinitionRouteLocator,这里以RouteDefinitionRouteLocator为例进行分析,代码如下:
kotlin
public class RouteDefinitionRouteLocator implements RouteLocator, BeanFactoryAware, ApplicationEventPublisherAware {
..........省略部分代码..........
private final RouteDefinitionLocator routeDefinitionLocator;
private final ConfigurationService configurationService;
private final Map<String, RoutePredicateFactory> predicates = new LinkedHashMap<>();
private final Map<String, GatewayFilterFactory> gatewayFilterFactories = new HashMap<>();
private final GatewayProperties gatewayProperties;
public Flux<Route> getRoutes() {
//将RouteDefinition集合转换为Route实例集合
Flux<Route> routes = this.routeDefinitionLocator.getRouteDefinitions().map(this::convertToRoute);
return routes.map(route -> {
return route;
});
}
}
getRoutes中this.routeDefinitionLocator.getRouteDefinitions获取所有的RouteDefinition,这个在上面已经分析过了,接下来分析下convertToRoute是如何将RouteDefinition转换为Route实例的:
scss
private Route convertToRoute(RouteDefinition routeDefinition) {
AsyncPredicate<ServerWebExchange> predicate = combinePredicates(routeDefinition);
List<GatewayFilter> gatewayFilters = getFilters(routeDefinition);
//使用构造器AsyncBuilder构造Route实例
return Route.async(routeDefinition).asyncPredicate(predicate)
.replaceFilters(gatewayFilters).build();
}
public static AsyncBuilder async(RouteDefinition routeDefinition) {
return new AsyncBuilder().id(routeDefinition.getId())
.uri(routeDefinition.getUri())
.order(routeDefinition.getOrder())
.metadata(routeDefinition.getMetadata());
}
public Route build() {
return new Route(this.id, this.uri, this.order, predicate, this.gatewayFilters, this.metadata);
}
这里使用了构造器AsyncBuilder来构造Route实例,Route.async首先从routeDefinition读取信息到构造器,然后设置构造器的Predicate和Filter,最后构造Route实例。
六、根据Http请求匹配Route:
1、流程:
SpringCloud Gateway依赖于框架Spring WebFlux,因此他的总入口不是DispatcherServlet而是DispatcherHandler,入口方法在handle中:
scss
public Mono<Void> handle(ServerWebExchange exchange) {
return Flux.fromIterable(this.handlerMappings)
//匹配到Route
.concatMap(mapping -> mapping.getHandler(exchange))
.next()
.switchIfEmpty(createNotFoundError())
//通过FilteringWebHandler执行过滤器链和执行业务代码
.flatMap(handler -> invokeHandler(exchange, handler))
//处理返回结果数据
.flatMap(result -> handleResult(exchange, result));
}
a、首先使用HandlerMapping从http请求匹配到Route,并返回FilteringWebHandler对象(mapping.getHandler(exchange));
b、接着通过FilteringWebHandler执行过滤器链和执行业务代码(invokeHandler(exchange, handler));
c、处理返回结果数据(handleResult(exchange, result));
2、HandlerMapping的初始化:
在DispatcherHandler的构造方法中从Spring容器过滤出所有实现了HandlerMapping接口的bean。
ini
public class DispatcherHandler implements WebHandler, ApplicationContextAware {
private List<HandlerMapping> handlerMappings;
private List<HandlerAdapter> handlerAdapters;
private List<HandlerResultHandler> resultHandlers;
public DispatcherHandler(ApplicationContext applicationContext) {
initStrategies(applicationContext);
}
protected void initStrategies(ApplicationContext context) {
Map<String, HandlerMapping> mappingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
this.handlerMappings = Collections.unmodifiableList(mappings);
Map<String, HandlerAdapter> adapterBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
this.handlerAdapters = new ArrayList<>(adapterBeans.values());
Map<String, HandlerResultHandler> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerResultHandler.class, true, false);
this.resultHandlers = new ArrayList<>(beans.values());
}
................
}
3、HandlerMapping匹配Route
HandlerMapping接口用于从http请求信息匹配到对应的Route,这个接只定义了一个方法getHandler,代码如下:
csharp
public interface HandlerMapping {
Mono<Object> getHandler(ServerWebExchange exchange);
}
HandlerMapping接口的实现类有很多,我们这里就分析下RoutePredicateHandlerMapping实现类是怎么匹配的流程:
scss
public Mono<Object> getHandler(ServerWebExchange exchange) {
return getHandlerInternal(exchange).map(handler -> {
return handler;
});
}
protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
//lookupRoute依据exchange匹配Route
return lookupRoute(exchange)
.flatMap((Function<Route, Mono<?>>) r -> {
exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r);
//返回FilteringWebHandler对象
return Mono.just(webHandler);
});
}
protected Mono<Route> lookupRoute(ServerWebExchange exchange) {
//routeLocator.getRoutes()返回所有的Route实例
return this.routeLocator.getRoutes()
.concatMap(route -> Mono.just(route).filterWhen(r -> {
exchange.getAttributes().put(GATEWAY_PREDICATE_ROUTE_ATTR, r.getId());
//过滤出断言为true的route
return r.getPredicate().apply(exchange);
}));
}
this.routeLocator.getRoutes返回所有的Route实例,这在上面已经分析过了。接下来遍历所有的Route,r.getPredicate().apply(exchange)对Route的断言进行判断,过滤出返回true的Route,至此匹配Route路由就完成。
getHandlerInternal最后返回的webHandler对象,从定义可以看到这个 webHandler是FilteringWebHandler类型的,也就是后面将交由他来执行过滤器链。
七、执行过滤器链和业务代码:
1、适配器HandlerAdapter:
由于HandlerMapping不止RoutePredicateHandlerMapping一种实现,还有其他实现,在RoutePredicateHandlerMapping实现中返回的是FilteringWebHandler(带过滤器链的webHandler),而其他类型中有的是返回WebSocketHandler,有的返回的是HandlerMethod(不带过滤器链的,直接执行业务代码)等等,要以一种统一的方式调用的话,就需要封装一个适配器接口HandlerAdapter:
java
public interface HandlerAdapter {
boolean supports(Object handler);
Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler);
}
supports用于判断持哪种类型的Handler,handle方法用于具体handler的调用。
执行业务代码的invokeHandler就是遍历所有的适配器HandlerAdapter,判断哪种适配器支持WebHandler则进行调用:
kotlin
private Mono<HandlerResult> invokeHandler(ServerWebExchange exchange, Object handler) {
if (this.handlerAdapters != null) {
for (HandlerAdapter handlerAdapter : this.handlerAdapters) {
if (handlerAdapter.supports(handler)) {
return handlerAdapter.handle(exchange, handler);
}
}
}
return Mono.error(new IllegalStateException("No HandlerAdapter: " + handler));
}
支持WebHandler的适配器是SimpleHandlerAdapter:
typescript
public class SimpleHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
return WebHandler.class.isAssignableFrom(handler.getClass());
}
@Override
public Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler) {
WebHandler webHandler = (WebHandler) handler;
//这里会进入FilteringWebHandler.handle的调用
Mono<Void> mono = webHandler.handle(exchange);
return mono.then(Mono.empty());
}
}
2、FilteringWebHandler的调用:
FilteringWebHandler首先加载全局过滤器:
java
public class FilteringWebHandler implements WebHandler {
private final List<GatewayFilter> globalFilters;
public FilteringWebHandler(List<GlobalFilter> globalFilters) {
this.globalFilters = loadFilters(globalFilters);
}
private static List<GatewayFilter> loadFilters(List<GlobalFilter> filters) {
return filters.stream().map(filter -> {
//利用适配器将GlobalFilter和GatewayFilter放到一个列表中
GatewayFilterAdapter gatewayFilter = new GatewayFilterAdapter(filter);
return gatewayFilter;
}).collect(Collectors.toList());
}
..............
}
private static class GatewayFilterAdapter implements GatewayFilter {
private final GlobalFilter delegate;
GatewayFilterAdapter(GlobalFilter delegate) {
this.delegate = delegate;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
return this.delegate.filter(exchange, chain);
}
}
全局过滤器GlobalFilter和Route过滤器GatewayFilter不是一个接口,不能放到一个集合中进行统一调用,因此定义了一个适配器GatewayFilterAdapter继承自GatewayFilter,这样两种过滤器就可以放到一个集合中统一调用了。
FilteringWebHandler的调用:
ini
public Mono<Void> handle(ServerWebExchange exchange) {
Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
List<GatewayFilter> gatewayFilters = route.getFilters();
//合并全局过滤器和Route过滤器
List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);
combined.addAll(gatewayFilters);
//交由DefaultGatewayFilterChain执行
return new DefaultGatewayFilterChain(combined).filter(exchange);
}
首先将全局过滤器和Route过滤器合并到一个集合,然后交由DefaultGatewayFilterChain执行:
kotlin
private static class DefaultGatewayFilterChain implements GatewayFilterChain {
//当前执行的过滤器的游标
private final int index;
//过滤器集合
private final List<GatewayFilter> filters;
DefaultGatewayFilterChain(List<GatewayFilter> filters) {
this.filters = filters;
this.index = 0;
}
private DefaultGatewayFilterChain(DefaultGatewayFilterChain parent, int index) {
this.filters = parent.getFilters();
this.index = index;
}
public List<GatewayFilter> getFilters() {
return filters;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange) {
return Mono.defer(() -> {
if (this.index < filters.size()) {
GatewayFilter filter = filters.get(this.index);
DefaultGatewayFilterChain chain = new DefaultGatewayFilterChain(this, this.index + 1);
//执行过滤器代码
return filter.filter(exchange, chain);
}
else {
return Mono.empty(); // complete
}
});
}
}
DefaultGatewayFilterChain是一个过滤器链,里面保存了一个过滤器集合和当前执行的游标,每次执行filter时,根据index取出过滤器执行,然后游标加一,将加一后的游标重新构造DefaultGatewayFilterChain去执行,直至所有的过滤器执行完成,最后返回Mono.empty()表示完成。
不对,所有过滤器执行完后不是应该再去执行业务代码吗,怎么返回Mono.empty()了,这样业务代码是不是就没地方执行了。断点调试看看过滤器链的数据,其中有过滤器NettyRoutingFilter和NettyWriteResponseFilter,NettyRoutingFilter负责发送请求到route目标地址服务执行,NettyWriteResponseFilter则负责将目标服务执行的结果输出到客户端。下面分别看看这两个过滤器。
3、请求业务代码和将执行结果写回客户端:
先看看NettyRoutingFilter的代码:
java
public class NettyRoutingFilter implements GlobalFilter, Ordered {
private final HttpClient httpClient;
private final HttpClientProperties properties;
@Override
public int getOrder() {
//排序在过滤器链集合最后
return Ordered.LOWEST_PRECEDENCE;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
URI requestUrl = exchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR);
String scheme = requestUrl.getScheme();
if (isAlreadyRouted(exchange) || (!"http".equals(scheme) && !"https".equals(scheme))) {
return chain.filter(exchange);
}
setAlreadyRouted(exchange);
........省略部分代码..........
ServerHttpRequest request = exchange.getRequest();
final HttpMethod method = HttpMethod.valueOf(request.getMethodValue());
final String url = requestUrl.toASCIIString();
Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
//getHttpClient返回的就是httpClient,这里将请求发送给后端微服务执行
Flux<HttpClientResponse> responseFlux = getHttpClient(route, exchange)
.request(method).uri(url).send((req, nettyOutbound) -> {
return nettyOutbound.send(request.getBody().map(this::getByteBuf));
});
//交给过滤器链的下一个过滤器执行
return responseFlux.then(chain.filter(exchange));
}
}
getOrder方法可以看到这个过滤器是排在过滤器链的最后面。filter方法首先获取业务服务真正的请求requestUrl,再用getHttpClient(route, exchange)获取到httpClient对象,接着调用httpClient向业务服务发送请求,将返回结果交由过滤器链的下一个过滤器来执行。
再看看NettyWriteResponseFilter的代码:
java
public class NettyWriteResponseFilter implements GlobalFilter, Ordered {
@Override
public int getOrder() {
//在过滤器链中的位置还是比较靠前的
return -1;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//chain.filter(exchange).then表示先交由过滤器链执行后面的过滤器,等后面的执行完成后再执行then后面的代码,相当于After Filter的效果
return chain.filter(exchange)
.then(Mono.defer(() -> {
//获取Connection
Connection connection = exchange.getAttribute(CLIENT_RESPONSE_CONN_ATTR);
if (connection == null) {
return Mono.empty();
}
//获取ServerHttpResponse
ServerHttpResponse response = exchange.getResponse();
//获取数据并转换数据
final Flux<DataBuffer> body = connection
.inbound()
.receive()
.retain()
.map(byteBuf -> wrap(byteBuf, response));
MediaType contentType = response.getHeaders().getContentType();
//writeAndFlushWith或writeWith都是将返回数据写回客户端
return (isStreamingMediaType(contentType)
? response.writeAndFlushWith(body.map(Flux::just))
: response.writeWith(body));
}));
}
}
getOrder的代码可以看到这个过滤器在过滤器链比较靠前的位置。filter方法,chain.filter(exchange).then表示先交由过滤器链执行后面的过滤器,等后面的执行完成后再执行then后面的代码,相当于After Filter的效果。then后面的代码首先获取Connection和ServerHttpResponse,接着获取返回业务请求返回数据并转换后的body,最后通过/writeAndFlushWith或writeWith都是将返回数据写回客户端。