前言
本章主要介绍一个Http请求的请求流程,下面是请求流程的流程图。
需要注意的是,这个请求流程中有个同名不同包的类,org.springframework.web.server.handler.FilteringWebHandler是SpringWeb的,org.springframework.cloud.gateway.handler.FilteringWebHandler是Gateway的,都实现了WebHandler接口,容易混淆。
一、DispatcherHandler之前
HttpWebHandlerAdapter#handle
创建ServerWebExchange
,委托ExceptionHandlingWebHandler
处理handle
方法。
@Override
public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {
// 创建ServerWebExchange
ServerWebExchange exchange = createExchange(request, response);
// 委托ExceptionHandlingWebHandler#handle
return getDelegate().handle(exchange)
.doOnSuccess(aVoid -> logResponse(exchange))
.onErrorResume(ex -> handleUnresolvedError(exchange, ex))
.then(Mono.defer(response::setComplete));
}
protected ServerWebExchange createExchange(ServerHttpRequest request, ServerHttpResponse response) {
return new DefaultServerWebExchange(request, response, this.sessionManager,
getCodecConfigurer(), getLocaleContextResolver(), this.applicationContext);
}
ExceptionHandlingWebHandler#handle
委托spring-web
的FilteringWebHandler
处理handle
方法。
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
Mono<Void> completion;
try {
// org.springframework.web.server.handler.WebHandlerDecorator#handle
// 委托org.springframework.web.server.handler.FilteringWebHandler#handle
completion = super.handle(exchange);
}
catch (Throwable ex) {
completion = Mono.error(ex);
}
// 全局异常处理
for (WebExceptionHandler handler : this.exceptionHandlers) {
completion = completion.onErrorResume(ex -> handler.handle(exchange, ex));
}
return completion;
}
FilteringWebHandler#handle
执行WebFilter过滤器链。
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
// 执行WebFilterChain的filter方法
return this.chain.filter(exchange);
}
DefaultWebFilterChain#filter
执行所有WebFilter,执行完毕后执行DispatcherHandler。
public class DefaultWebFilterChain implements WebFilterChain {
// 所有过滤器
private final List<WebFilter> allFilters;
// DispatcherHandler
private final WebHandler handler;
// 当前需要执行的过滤器
private final WebFilter currentFilter;
// 剩下需要处理的过滤器链
private final DefaultWebFilterChain chain;
@Override
public Mono<Void> filter(ServerWebExchange exchange) {
return Mono.defer(() ->
this.currentFilter != null && this.chain != null ?
// 执行WebFilter
invokeFilter(this.currentFilter, this.chain, exchange) :
// 执行DispatcherHandler
this.handler.handle(exchange));
}
private Mono<Void> invokeFilter(WebFilter current, DefaultWebFilterChain chain, ServerWebExchange exchange) {
String currentName = current.getClass().getName();
return current.filter(exchange, chain).checkpoint(currentName + " [DefaultWebFilterChain]");
}
二、DispatcherHandler执行流程
DispatcherHandler#handle
和SpringMVC的DispatcherServlet
类似。
public class DispatcherHandler implements WebHandler, ApplicationContextAware {
private List<HandlerMapping> handlerMappings;
private List<HandlerAdapter> handlerAdapters;
private List<HandlerResultHandler> resultHandlers;
public Mono<Void> handle(ServerWebExchange exchange) {
if (this.handlerMappings == null) {
return createNotFoundError();
}
return Flux.fromIterable(this.handlerMappings)
// 按照优先级执行HandlerMapping的getHandler方法获取handler
// 抽象父类AbstractHandlerMapping#getHandler会调用子类的getHandlerInternal方法
.concatMap(mapping -> mapping.getHandler(exchange))
// 取得到的第一个handler
.next()
// 找不到handler抛异常
.switchIfEmpty(createNotFoundError())
// 循环HandlerAdapter,找到合适的Adapter执行handler
.flatMap(handler -> invokeHandler(exchange, handler))
// 循环HandlerResultHandler,找到合适的执行handleResult方法返回客户端
.flatMap(result -> handleResult(exchange, result));
}
}
RoutePredicateHandlerMapping
RoutePredicateHandlerMapping根据ServerWebExchange获取Handler,将Route实例放入ServerWebExchange的Attribute中,后续一直会用到exchange实例里的Route实例。
public class RoutePredicateHandlerMapping extends AbstractHandlerMapping {
private final FilteringWebHandler webHandler;
private final RouteLocator routeLocator;
public RoutePredicateHandlerMapping(FilteringWebHandler webHandler,
RouteLocator routeLocator, GlobalCorsProperties globalCorsProperties,
Environment environment) {
this.webHandler = webHandler;
this.routeLocator = routeLocator;
setOrder(1);
}
}
getHandlerInternal
根据ServerWebExchange,找到Route放入ServerWebExchange的Attribute,返回FilteringWebHandler实例。
@Override
protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
// GATEWAY_HANDLER_MAPPER_ATTR = 'RoutePredicateHandlerMapping'
exchange.getAttributes().put(GATEWAY_HANDLER_MAPPER_ATTR, getSimpleName());
// 根据exchange找到Route实例
return lookupRoute(exchange)
.flatMap((Function<Route, Mono<?>>) r -> {
// 移除lookupRoute添加的Attribute:GATEWAY_PREDICATE_ROUTE_ATTR
exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
// 把Route实例放入Attribute
// 后续Gateway的Filter基本都会用到这个Route实例,很重要
exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r);
// 返回FilteringWebHandler实例
return Mono.just(webHandler);
}).switchIfEmpty(Mono.empty().then(Mono.fromRunnable(() -> {
// 移除lookupRoute添加的Attribute:GATEWAY_PREDICATE_ROUTE_ATTR
exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
})));
}
// 根据ServerWebExchange找到Route
protected Mono<Route> lookupRoute(ServerWebExchange exchange) {
// CachingRouteLocator获取Route
return this.routeLocator.getRoutes()
// 调用Route的断言的apply方法,过滤出满足条件的Route
.concatMap(route -> Mono.just(route).filterWhen(r -> {
exchange.getAttributes().put(GATEWAY_PREDICATE_ROUTE_ATTR, r.getId());
return r.getPredicate().apply(exchange);
})
.doOnError(e -> logger.error(
"Error applying predicate for route: " + route.getId(),
e))
.onErrorResume(e -> Mono.empty()))
// 选取第一个过滤出来的Route
.next()
.map(route -> {
// 校验Route,默认空实现
validateRoute(route, exchange);
return route;
});
}
FilteringWebHandler
SimpleHandlerAdapter#handle
执行FilteringWebHandler
。
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;
Mono<Void> mono = webHandler.handle(exchange);
return mono.then(Mono.empty());
}
}
FilteringWebHandler
执行所有GatewayFilter。
public class FilteringWebHandler implements WebHandler {
private final List<GatewayFilter> globalFilters;
public FilteringWebHandler(List<GlobalFilter> globalFilters) {
// 这里会把GlobalFilter全局过滤器适配成GatewayFilter,逻辑省略
this.globalFilters = loadFilters(globalFilters);
}
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
// RoutePredicateHandlerMapping#getHandlerInternal的时候放入的Route实例
Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
// 获取Route实例上的GatewayFilter
List<GatewayFilter> gatewayFilters = route.getFilters();
// 组合全局GatewayFilter
List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);
combined.addAll(gatewayFilters);
// 排序
AnnotationAwareOrderComparator.sort(combined);
// DefaultGatewayFilterChain.filter执行网关过滤器链
return new DefaultGatewayFilterChain(combined).filter(exchange);
}
}
DefaultGatewayFilterChain通过filters列表和移动下标的方式串联成一个过滤器链。
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;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange) {
return Mono.defer(() -> {
// 如果还有过滤器没执行,则执行
if (this.index < filters.size()) {
// 获取当前过滤器
GatewayFilter filter = filters.get(this.index);
// 移动下标,构造一个新的链表(只是移动了下标,filters还是原始的filters)
// 给后续执行的filter调用chain.filter
DefaultGatewayFilterChain chain = new DefaultGatewayFilterChain(this,
this.index + 1);
// 执行filter
return filter.filter(exchange, chain);
}
else {
return Mono.empty();
}
});
}
}
三、重要的GlobalFilter
RouteToRequestUrlFilter
用Route的URI,替换原始请求url里的协议、host、port。如原始请求为:
http://localhost:60261/httpbin/get
,替换为lb://httpbin/httpbin/get
,协议由http替换为lb,localhost:60261替换为httpbin。
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
// 原始URL
URI uri = exchange.getRequest().getURI();
// Route的URL
URI routeUri = route.getUri();
URI mergedUrl = UriComponentsBuilder.fromUri(uri)
// 协议替换
.scheme(routeUri.getScheme())
// host替换
.host(routeUri.getHost())
// 端口替换
.port(routeUri.getPort())
.build(encoded).toUri();
// 保存合并后的url
exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, mergedUrl);
return chain.filter(exchange);
}
LoadBalancerClientFilter
使用Ribbon的LoadBalancerClient重构请求URL。
public class LoadBalancerClientFilter implements GlobalFilter, Ordered {
public static final int LOAD_BALANCER_CLIENT_FILTER_ORDER = 10100;
protected final LoadBalancerClient loadBalancer;
private LoadBalancerProperties properties;
public LoadBalancerClientFilter(LoadBalancerClient loadBalancer,
LoadBalancerProperties properties) {
this.loadBalancer = loadBalancer;
this.properties = properties;
}
@Override
public int getOrder() {
return LOAD_BALANCER_CLIENT_FILTER_ORDER;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
URI url = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR);
String schemePrefix = exchange.getAttribute(GATEWAY_SCHEME_PREFIX_ATTR);
// 非lb协议直接通过
if (url == null
|| (!"lb".equals(url.getScheme()) && !"lb".equals(schemePrefix))) {
return chain.filter(exchange);
}
// 保存原始url
addOriginalRequestUrl(exchange, url);
// 使用负载均衡策略,获取ServiceInstance
final ServiceInstance instance = choose(exchange);
if (instance == null) {
throw NotFoundException.create(properties.isUse404(),
"Unable to find instance for " + url.getHost());
}
// 获取schema,attribute里的优先,其次是ServiceInstance.isSecure
URI uri = exchange.getRequest().getURI();
String overrideScheme = instance.isSecure() ? "https" : "http";
if (schemePrefix != null) {
overrideScheme = url.getScheme();
}
// reconstructURI重构URL
URI requestUrl = loadBalancer.reconstructURI(
new DelegatingServiceInstance(instance, overrideScheme), uri);
if (log.isTraceEnabled()) {
log.trace("LoadBalancerClientFilter url chosen: " + requestUrl);
}
// 设置请求URL
exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, requestUrl);
return chain.filter(exchange);
}
protected ServiceInstance choose(ServerWebExchange exchange) {
return loadBalancer.choose(
((URI) exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR)).getHost());
}
}
NettyRoutingFilter
请求后端服务。重点关注一下连接超时时间、响应超时时间的获取。
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
URI requestUrl = exchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR);
ServerHttpRequest request = exchange.getRequest();
final HttpMethod method = HttpMethod.valueOf(request.getMethodValue());
final String url = requestUrl.toASCIIString();
boolean preserveHost = exchange
.getAttributeOrDefault(PRESERVE_HOST_HEADER_ATTRIBUTE, false);
Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
// 获取HttpClientConnect
Flux<HttpClientResponse> responseFlux = getHttpClient(route, exchange)
.headers(headers -> {
// 请求头处理...
}).request(method).uri(url).send((req, nettyOutbound) -> {
return nettyOutbound.send(request.getBody().map(this::getByteBuf));
// responseConnection发起请求
}).responseConnection((res, connection) -> {
// 返回响应
return Mono.just(res);
});
// 获取响应超时时间
Duration responseTimeout = getResponseTimeout(route);
if (responseTimeout != null) {
// 响应超时处理
responseFlux = responseFlux
.timeout(responseTimeout, Mono.error(new TimeoutException(
"Response took longer than timeout: " + responseTimeout)))
.onErrorMap(TimeoutException.class,
th -> new ResponseStatusException(HttpStatus.GATEWAY_TIMEOUT,
th.getMessage(), th));
}
return responseFlux.then(chain.filter(exchange));
}
getHttpClient
获取HttpClient,可以用Route的Metadata的CONNECT_TIMEOUT_ATTR属性,定制连接超时时间。默认取httpClient构造时的配置,默认45秒spring.cloud.gateway.httpclient.connectTimeout=4500
。
protected HttpClient getHttpClient(Route route, ServerWebExchange exchange) {
Object connectTimeoutAttr = route.getMetadata().get(CONNECT_TIMEOUT_ATTR);
if (connectTimeoutAttr != null) {
Integer connectTimeout = getInteger(connectTimeoutAttr);
return this.httpClient.tcpConfiguration((tcpClient) -> tcpClient
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, connectTimeout));
}
return httpClient;
}
getResponseTimeout
获取响应超时时间,优先取Route的Metadata里的RESPONSE_TIMEOUT_ATTR属性,默认取spring.cloud.gateway.httpclient.responseTimeout
为空,没有响应超时时间。
private Duration getResponseTimeout(Route route) {
Object responseTimeoutAttr = route.getMetadata().get(RESPONSE_TIMEOUT_ATTR);
Long responseTimeout = null;
if (responseTimeoutAttr != null) {
if (responseTimeoutAttr instanceof Number) {
responseTimeout = ((Number) responseTimeoutAttr).longValue();
}
else {
responseTimeout = Long.valueOf(responseTimeoutAttr.toString());
}
}
return responseTimeout != null ? Duration.ofMillis(responseTimeout)
: properties.getResponseTimeout();
}
NettyWriteResponseFilter
Mono.then写response
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
return chain.filter(exchange)
.doOnError(throwable -> cleanup(exchange))
.then(Mono.defer(() -> {
Connection connection = exchange.getAttribute(CLIENT_RESPONSE_CONN_ATTR);
if (connection == null) {
return Mono.empty();
}
ServerHttpResponse response = exchange.getResponse();
final Flux<DataBuffer> body = connection
.inbound()
.receive()
.retain()
.map(byteBuf -> wrap(byteBuf, response));
MediaType contentType = response.getHeaders().getContentType();
return (isStreamingMediaType(contentType)
? response.writeAndFlushWith(body.map(Flux::just))
: response.writeWith(body));
})).doOnCancel(() -> cleanup(exchange));
}
总结
- 请求流程中关键的两个类
- RoutePredicateHandlerMapping断言匹配获取Route
- FilteringWebHandler执行所有GatewayFilter
- LoadBalancerClientFilter利用Ribbon的LoadBalancerClient实现负载均衡
- SpringCloudGateway调用后端服务的两个超时时间需要自己配置一下