文章目录
- 一、背景
- 1. 核心概念
- 2. 工作流程
- 3.动态路由
- 二、自动配置源码解析
- 1.GatewayAutoConfiguration
- 2.WebFluxAutoConfiguration
- 3.HttpHandlerAutoConfiguration
- 三、请求过程源码解析
- 1. 整体流程
- 2. NettyWebServer接收http请求
- 3.请求和响应转换
- 4.HttpWebHandlerAdapter
- 5. ExceptionHandlingWebHandler
- 6. DispatcherHandler
- 7.FilteringWebHandler
- 8.ReactiveLoadBalancerClientFilter
- 9.NettyRoutingFilter
一、背景
使用Spring cloud开发微服务系统,一般采用的架构如下所示,Gateway不仅作为请求转发的入口,还会进行权限验证、监控、缓存、请求路由、流量限制、请求熔断、请求重试等功能。Spring Cloud Gateway作为Spring Cloud体系中API网关。
1. 核心概念
Spring Cloud GateWay 最主要的功能就是路由转发,而在定义转发规则时主要涉及了以下三个核心概念:
- Route
网关最基本的模块。它由一个 ID、一个目标 URI、一组断言(Predicate)和一组过滤器(Filter)组成。 - Predicate
路由转发的判断条件,我们可以通过 Predicate 对 HTTP 请求进行匹配,例如请求方式、请求路径、请求头、参数等,如果请求与断言匹配成功,则将请求转发到相应的服务。
Route 路由与 Predicate 断言的对应关系为“一对多”,一个路由可以包含多个不同断言。一个请求想要转发到指定的路由上,就必须同时匹配路由上的所有断言。当一个请求同时满足多个路由的断言条件时,请求只会被首个成功匹配的路由转发。 - Filter
过滤器,我们可以使用它对请求进行拦截和修改,还可以使用它对上文的响应进行再处理。
2. 工作流程
Spring Cloud Gateway 工作流程说明如下:
- 客户端将请求发送到 Spring Cloud Gateway 上。
- Spring Cloud Gateway 通过 Gateway Handler Mapping 找到与请求相匹配的路由,将其发送给 Gateway Web Handler。
- Gateway Web Handler 通过指定的过滤器链(Filter Chain),将请求转发到实际的服务节点中,执行业务逻辑返回响应结果。
- 过滤器之间用虚线分开是因为过滤器可能会在转发请求之前(pre)或之后(post)执行业务逻辑。
- 过滤器(Filter)可以在请求被转发到服务端前,对请求进行拦截和修改,例如参数校验、权限校验、流量监控、日志输出以及协议转换等。
- 过滤器可以在响应返回客户端之前,对响应进行拦截和再处理,例如修改响应内容或响应头、日志输出、流量监控等。
响应原路返回给客户端。
3.动态路由
默认情况下,Spring Cloud Gateway 会根据服务注册中心(例如 Eureka Server)中维护的服务列表,以服务名(spring.application.name)作为路径创建动态路由进行转发,从而实现动态路由功能。可以在配置文件中,将 Route 的 uri 地址修改为以下形式。
lb://service-name
以上配置说明如下:
lb:uri 的协议,表示开启 Spring Cloud Gateway 的负载均衡功能。
service-name:服务名,Spring Cloud Gateway 会根据它获取到具体的微服务地址。
二、自动配置源码解析
1.GatewayAutoConfiguration
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true)
@EnableConfigurationProperties
// HttpHandlerAutoConfiguration.class 中自动配置了HttpHandler
// WebFluxAutoConfiguration.class 中自动配置了DispatcherHandler
@AutoConfigureBefore({ HttpHandlerAutoConfiguration.class, WebFluxAutoConfiguration.class })
@AutoConfigureAfter({ GatewayReactiveLoadBalancerClientAutoConfiguration.class,
GatewayClassPathWarningAutoConfiguration.class })
@ConditionalOnClass(DispatcherHandler.class)
public class GatewayAutoConfiguration {
@Bean
@Primary
@ConditionalOnMissingBean(name = "cachedCompositeRouteLocator")
// TODO: property to disable composite?
public RouteLocator cachedCompositeRouteLocator(List<RouteLocator> routeLocators) {
// yml文件routes配置内容
return new CachingRouteLocator(new CompositeRouteLocator(Flux.fromIterable(routeLocators)));
}
@Bean
public FilteringWebHandler filteringWebHandler(List<GlobalFilter> globalFilters) {
// 创建FilteringWebHandler, 即RoutePredicateHandlerMapping#webHandler
return new FilteringWebHandler(globalFilters);
}
@Bean
@ConditionalOnMissingBean
public RoutePredicateHandlerMapping routePredicateHandlerMapping(FilteringWebHandler webHandler,
RouteLocator routeLocator, GlobalCorsProperties globalCorsProperties, Environment environment) {
// DispatcherHandler中HandlerMapping 之一,实际进行HandlerMapping匹配
return new RoutePredicateHandlerMapping(webHandler, routeLocator, globalCorsProperties, environment);
}
...
}
2.WebFluxAutoConfiguration
@AutoConfiguration(after = { ReactiveWebServerFactoryAutoConfiguration.class, CodecsAutoConfiguration.class,
ReactiveMultipartAutoConfiguration.class, ValidationAutoConfiguration.class,
WebSessionIdResolverAutoConfiguration.class })
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
@ConditionalOnClass(WebFluxConfigurer.class)
@ConditionalOnMissingBean({ WebFluxConfigurationSupport.class })
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
public class WebFluxAutoConfiguration {
...
/**
* Configuration equivalent to {@code @EnableWebFlux}.
*/
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties({ WebProperties.class, ServerProperties.class })
public static class EnableWebFluxConfiguration extends DelegatingWebFluxConfiguration {
}
}
EnableWebFluxConfiguration 的继承关系如下:
DispatcherHandler在WebFluxConfigurationSupport中进行实例化
@Bean
public DispatcherHandler webHandler() {
// 实际将http请求,装换到HttpWebHandlerAdapter进行处理
return new DispatcherHandler();
}
3.HttpHandlerAutoConfiguration
@AutoConfiguration(after = { WebFluxAutoConfiguration.class })
@ConditionalOnClass({ DispatcherHandler.class, HttpHandler.class })
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
@ConditionalOnMissingBean(HttpHandler.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
public class HttpHandlerAutoConfiguration {
@Configuration(proxyBeanMethods = false)
public static class AnnotationConfig {
private final ApplicationContext applicationContext;
public AnnotationConfig(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Bean
public HttpHandler httpHandler(ObjectProvider<WebFluxProperties> propsProvider) {
// 创建HttpHanlder
HttpHandler httpHandler = WebHttpHandlerBuilder.applicationContext(this.applicationContext).build();
WebFluxProperties properties = propsProvider.getIfAvailable();
if (properties != null && StringUtils.hasText(properties.getBasePath())) {
Map<String, HttpHandler> handlersMap = Collections.singletonMap(properties.getBasePath(), httpHandler);
return new ContextPathCompositeHandler(handlersMap);
}
return httpHandler;
}
}
}
public static WebHttpHandlerBuilder applicationContext(ApplicationContext context) {
// 获取名称为WEB_HANDLER_BEAN_NAME,类型为WebHandler的Bean
WebHttpHandlerBuilder builder = new WebHttpHandlerBuilder(
context.getBean(WEB_HANDLER_BEAN_NAME, WebHandler.class), context);
// 获取WebFilter类型的Filter
List<WebFilter> webFilters = context
.getBeanProvider(WebFilter.class)
.orderedStream()
.collect(Collectors.toList());
builder.filters(filters -> filters.addAll(webFilters));
// 获取WebExceptionHandler类型的Handler
List<WebExceptionHandler> exceptionHandlers = context
.getBeanProvider(WebExceptionHandler.class)
.orderedStream()
.collect(Collectors.toList());
builder.exceptionHandlers(handlers -> handlers.addAll(exceptionHandlers));
context.getBeanProvider(HttpHandlerDecoratorFactory.class)
.orderedStream()
.forEach(builder::httpHandlerDecorator);
try {
// 设置session管理器
builder.sessionManager(
context.getBean(WEB_SESSION_MANAGER_BEAN_NAME, WebSessionManager.class));
}
catch (NoSuchBeanDefinitionException ex) {
// Fall back on default
}
try {
// 设置编解码器
builder.codecConfigurer(
context.getBean(SERVER_CODEC_CONFIGURER_BEAN_NAME, ServerCodecConfigurer.class));
}
catch (NoSuchBeanDefinitionException ex) {
// Fall back on default
}
try {
builder.localeContextResolver(
context.getBean(LOCALE_CONTEXT_RESOLVER_BEAN_NAME, LocaleContextResolver.class));
}
catch (NoSuchBeanDefinitionException ex) {
// Fall back on default
}
try {
builder.forwardedHeaderTransformer(
context.getBean(FORWARDED_HEADER_TRANSFORMER_BEAN_NAME, ForwardedHeaderTransformer.class));
}
catch (NoSuchBeanDefinitionException ex) {
// Fall back on default
}
return builder;
}
// 生成HttpBuilder
public HttpHandler build() {
// 将DispatcherHandler,和过滤器组合使用装饰器组成WebHandler
WebHandler decorated = new FilteringWebHandler(this.webHandler, this.filters);
// 再将exceptionHandlers放到装饰器,组成ExceptionHandlingWebHandler
decorated = new ExceptionHandlingWebHandler(decorated, this.exceptionHandlers);
// 将WebHandler通过转换器实现HttpHandler的handle方法
HttpWebHandlerAdapter adapted = new HttpWebHandlerAdapter(decorated);
if (this.sessionManager != null) {
// 设置session管理器
adapted.setSessionManager(this.sessionManager);
}
if (this.codecConfigurer != null) {
// 设置编解码器
adapted.setCodecConfigurer(this.codecConfigurer);
}
if (this.localeContextResolver != null) {
// 设置LocaleContextResolver
adapted.setLocaleContextResolver(this.localeContextResolver);
}
if (this.forwardedHeaderTransformer != null) {
// 设置http hedaer 转换器
adapted.setForwardedHeaderTransformer(this.forwardedHeaderTransformer);
}
if (this.applicationContext != null) {
// 设置applicationContext
adapted.setApplicationContext(this.applicationContext);
}
adapted.afterPropertiesSet();
return (this.httpHandlerDecorator != null ? this.httpHandlerDecorator.apply(adapted) : adapted);
}
三、请求过程源码解析
1. 整体流程
下图的请求过程,是对Spring Cloud Gateway工作流程的细化
2. NettyWebServer接收http请求
NettyWebServer是通过HttpServer来接收http请求
public void onStateChange(Connection connection, State newState) {
// 接收到http 请求事件,则进行处理
if (newState == HttpServerState.REQUEST_RECEIVED) {
try {
if (log.isDebugEnabled()) {
log.debug(format(connection.channel(), "Handler is being applied: {}"), handler);
}
HttpServerOperations ops = (HttpServerOperations) connection;
// 调用ReactorHttpHandlerAdapter进行请求处理
Publisher<Void> publisher = handler.apply(ops, ops);
Mono<Void> mono = Mono.deferContextual(ctx -> {
ops.currentContext = Context.of(ctx);
return Mono.fromDirect(publisher);
});
if (ops.mapHandle != null) {
mono = ops.mapHandle.apply(mono, connection);
}
mono.subscribe(ops.disposeSubscriber());
}
catch (Throwable t) {
log.error(format(connection.channel(), ""), t);
//"FutureReturnValueIgnored" this is deliberate
connection.channel()
.close();
}
}
}
3.请求和响应转换
ReactorHttpHandlerAdapter主要是将NettyServer中http的请求和响应,装换为ReactorServerHttpRequest 和 ReactorServerHttpResponse。
@Override
public Mono<Void> apply(HttpServerRequest reactorRequest, HttpServerResponse reactorResponse) {
NettyDataBufferFactory bufferFactory = new NettyDataBufferFactory(reactorResponse.alloc());
try {
// 将NettyServer中http的请求和响应,装换为ReactorServerHttpRequest 和 ReactorServerHttpResponse
ReactorServerHttpRequest request = new ReactorServerHttpRequest(reactorRequest, bufferFactory);
ServerHttpResponse response = new ReactorServerHttpResponse(reactorResponse, bufferFactory);
if (request.getMethod() == HttpMethod.HEAD) {
response = new HttpHeadResponseDecorator(response);
}
// 调用DelayedInitializationHttpHandler进行http请求处理,DelayedInitializationHttpHandler直接将请求转给HttpWebHandlerAdapter
return this.httpHandler.handle(request, response)
.doOnError(ex -> logger.trace(request.getLogPrefix() + "Failed to complete: " + ex.getMessage()))
.doOnSuccess(aVoid -> logger.trace(request.getLogPrefix() + "Handling completed"));
}
catch (URISyntaxException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to get request URI: " + ex.getMessage());
}
reactorResponse.status(HttpResponseStatus.BAD_REQUEST);
return Mono.empty();
}
}
4.HttpWebHandlerAdapter
@Override
public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {
if (this.forwardedHeaderTransformer != null) {
try {
// 处理http 请求头中:Forwarded、X-Forwarded-Host、X-Forwarded-Port、X-Forwarded-Proto、X-Forwarded-Prefix、X-Forwarded-Ssl、X-Forwarded-For,包装请求来覆盖其host、端口和scheme方案
request = this.forwardedHeaderTransformer.apply(request);
}
catch (Throwable ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to apply forwarded headers to " + formatRequest(request), ex);
}
response.setStatusCode(HttpStatus.BAD_REQUEST);
return response.setComplete();
}
}
// 将http 请求和响应,装换为DefaultServerWebExchange
ServerWebExchange exchange = createExchange(request, response);
LogFormatUtils.traceDebug(logger, traceOn ->
exchange.getLogPrefix() + formatRequest(exchange.getRequest()) +
(traceOn ? ", headers=" + formatHeaders(exchange.getRequest().getHeaders()) : ""));
// 调用ExceptionHandlingWebHandler 进行处理
return getDelegate().handle(exchange)
.doOnSuccess(aVoid -> logResponse(exchange))
.onErrorResume(ex -> handleUnresolvedError(exchange, ex))
.then(Mono.defer(response::setComplete));
}
5. ExceptionHandlingWebHandler
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
Mono<Void> completion;
try {
// 调用DispatcherHandler进行处理
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;
}
6. DispatcherHandler
DispatcherHandler是一个很重要的处理类,处理的主流程是handle,选匹配handlerMapping,再执行invokeHandler,最后执行handleResult。
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
if (this.handlerMappings == null) {
return createNotFoundError();
}
// Cors预请求检测:Method为Options,请求头包括:Origin、Access-Control-Request-Method,Cors详情见:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS
// Cors: 浏览器必须首先使用 OPTIONS 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨源请求
if (CorsUtils.isPreFlightRequest(exchange.getRequest())) {
return handlePreFlight(exchange);
}
return Flux.fromIterable(this.handlerMappings)
// rote通过predicates匹配,是否支持该请求
.concatMap(mapping -> mapping.getHandler(exchange))
.next()
// 没有找到请求处理器,返回404
.switchIfEmpty(createNotFoundError())
// 调用请求
.flatMap(handler -> invokeHandler(exchange, handler))
// 处理返回结果
.flatMap(result -> handleResult(exchange, result));
}
@Override
public Mono<Void> handlePreFlight(ServerWebExchange exchange) {
return Flux.fromIterable(this.handlerMappings != null ? this.handlerMappings : Collections.emptyList())
.concatMap(mapping -> mapping.getHandler(exchange))
// cors预请求在匹配为空,返回403
.switchIfEmpty(Mono.fromRunnable(() -> exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN)))
.next()
.then();
}
private Mono<HandlerResult> invokeHandler(ServerWebExchange exchange, Object handler) {
if (ObjectUtils.nullSafeEquals(exchange.getResponse().getStatusCode(), HttpStatus.FORBIDDEN)) {
return Mono.empty(); // CORS rejection
}
if (this.handlerAdapters != null) {
for (HandlerAdapter handlerAdapter : this.handlerAdapters) {
// 判断handlerAdapter 是否支持 handler
if (handlerAdapter.supports(handler)) {
// 调用 SimpleHandlerAdapter 执行请求,实际代理为FilteringWebHandler进行执行
return handlerAdapter.handle(exchange, handler);
}
}
}
return Mono.error(new IllegalStateException("No HandlerAdapter: " + handler));
}
private Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {
// http响应处理
return getResultHandler(result).handleResult(exchange, result)
.checkpoint("Handler " + result.getHandler() + " [DispatcherHandler]")
.onErrorResume(ex ->
result.applyExceptionHandler(ex).flatMap(exResult -> {
String text = "Exception handler " + exResult.getHandler() +
", error=\"" + ex.getMessage() + "\" [DispatcherHandler]";
return getResultHandler(exResult).handleResult(exchange, exResult).checkpoint(text);
}));
}
private HandlerResultHandler getResultHandler(HandlerResult handlerResult) {
if (this.resultHandlers != null) {
for (HandlerResultHandler resultHandler : this.resultHandlers) {
if (resultHandler.supports(handlerResult)) {
return resultHandler;
}
}
}
throw new IllegalStateException("No HandlerResultHandler for " + handlerResult.getReturnValue());
}
7.FilteringWebHandler
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
// 获取匹配route中配置的filters
List<GatewayFilter> gatewayFilters = route.getFilters();
// 全局Filters
List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);
// 添加route中的filters
combined.addAll(gatewayFilters);
// 排序
AnnotationAwareOrderComparator.sort(combined);
if (logger.isDebugEnabled()) {
logger.debug("Sorted gatewayFilterFactories: " + combined);
}
// 创建Filter调用链
return new DefaultGatewayFilterChain(combined).filter(exchange);
}
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);
// 依次调用filter,其中最重要的是ReactiveLoadBalancerClientFilter,NettyRoutingFilter
return filter.filter(exchange, chain);
}
else {
return Mono.empty(); // complete
}
});
}
}
8.ReactiveLoadBalancerClientFilter
这个是负载均衡Filter。
@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);
if (url == null || (!"lb".equals(url.getScheme()) && !"lb".equals(schemePrefix))) {
return chain.filter(exchange);
}
// preserve the original url
addOriginalRequestUrl(exchange, url);
if (log.isTraceEnabled()) {
log.trace(ReactiveLoadBalancerClientFilter.class.getSimpleName() + " url before: " + url);
}
URI requestUri = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR);
String serviceId = requestUri.getHost();
Set<LoadBalancerLifecycle> supportedLifecycleProcessors = LoadBalancerLifecycleValidator
.getSupportedLifecycleProcessors(clientFactory.getInstances(serviceId, LoadBalancerLifecycle.class),
RequestDataContext.class, ResponseData.class, ServiceInstance.class);
DefaultRequest<RequestDataContext> lbRequest = new DefaultRequest<>(
new RequestDataContext(new RequestData(exchange.getRequest()), getHint(serviceId)));
LoadBalancerProperties loadBalancerProperties = clientFactory.getProperties(serviceId);
// 负载均衡选择转发实例
return choose(lbRequest, serviceId, supportedLifecycleProcessors).doOnNext(response -> {
if (!response.hasServer()) {
supportedLifecycleProcessors.forEach(lifecycle -> lifecycle
.onComplete(new CompletionContext<>(CompletionContext.Status.DISCARD, lbRequest, response)));
throw NotFoundException.create(properties.isUse404(), "Unable to find instance for " + url.getHost());
}
ServiceInstance retrievedInstance = response.getServer();
URI uri = exchange.getRequest().getURI();
// if the `lb:<scheme>` mechanism was used, use `<scheme>` as the default,
// if the loadbalancer doesn't provide one.
String overrideScheme = retrievedInstance.isSecure() ? "https" : "http";
if (schemePrefix != null) {
overrideScheme = url.getScheme();
}
DelegatingServiceInstance serviceInstance = new DelegatingServiceInstance(retrievedInstance,
overrideScheme);
// 转发uri
URI requestUrl = reconstructURI(serviceInstance, uri);
if (log.isTraceEnabled()) {
log.trace("LoadBalancerClientFilter url chosen: " + requestUrl);
}
// 设置实际转发uri
exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, requestUrl);
exchange.getAttributes().put(GATEWAY_LOADBALANCER_RESPONSE_ATTR, response);
supportedLifecycleProcessors.forEach(lifecycle -> lifecycle.onStartRequest(lbRequest, response));
}).then(chain.filter(exchange))
.doOnError(throwable -> supportedLifecycleProcessors.forEach(lifecycle -> lifecycle
.onComplete(new CompletionContext<ResponseData, ServiceInstance, RequestDataContext>(
CompletionContext.Status.FAILED, throwable, lbRequest,
exchange.getAttribute(GATEWAY_LOADBALANCER_RESPONSE_ATTR)))))
.doOnSuccess(aVoid -> supportedLifecycleProcessors.forEach(lifecycle -> lifecycle
.onComplete(new CompletionContext<ResponseData, ServiceInstance, RequestDataContext>(
CompletionContext.Status.SUCCESS, lbRequest,
exchange.getAttribute(GATEWAY_LOADBALANCER_RESPONSE_ATTR), buildResponseData(exchange,
loadBalancerProperties.isUseRawStatusCodeInResponseData())))));
}
9.NettyRoutingFilter
这个是实际请求http转发请求的Filter。
@Override
@SuppressWarnings("Duplicates")
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
URI requestUrl = exchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR);
String scheme = requestUrl.getScheme();
if (isAlreadyRouted(exchange) || (!"http".equalsIgnoreCase(scheme) && !"https".equalsIgnoreCase(scheme))) {
return chain.filter(exchange);
}
setAlreadyRouted(exchange);
ServerHttpRequest request = exchange.getRequest();
final HttpMethod method = HttpMethod.valueOf(request.getMethodValue());
final String url = requestUrl.toASCIIString();
HttpHeaders filtered = filterRequest(getHeadersFilters(), exchange);
final DefaultHttpHeaders httpHeaders = new DefaultHttpHeaders();
filtered.forEach(httpHeaders::set);
boolean preserveHost = exchange.getAttributeOrDefault(PRESERVE_HOST_HEADER_ATTRIBUTE, false);
Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
Flux<HttpClientResponse> responseFlux = getHttpClient(route, exchange).headers(headers -> {
headers.add(httpHeaders);
// Will either be set below, or later by Netty
headers.remove(HttpHeaders.HOST);
if (preserveHost) {
String host = request.getHeaders().getFirst(HttpHeaders.HOST);
headers.add(HttpHeaders.HOST, host);
}
})
// http请求转发
.request(method).uri(url).send((req, nettyOutbound) -> {
if (log.isTraceEnabled()) {
nettyOutbound.withConnection(connection -> log.trace("outbound route: "
+ connection.channel().id().asShortText() + ", inbound: " + exchange.getLogPrefix()));
}
return nettyOutbound.send(request.getBody().map(this::getByteBuf));
}).responseConnection((res, connection) -> {
// Defer committing the response until all route filters have run
// Put client response as ServerWebExchange attribute and write
// response later NettyWriteResponseFilter
exchange.getAttributes().put(CLIENT_RESPONSE_ATTR, res);
exchange.getAttributes().put(CLIENT_RESPONSE_CONN_ATTR, connection);
ServerHttpResponse response = exchange.getResponse();
// put headers and status so filters can modify the response
HttpHeaders headers = new HttpHeaders();
res.responseHeaders().forEach(entry -> headers.add(entry.getKey(), entry.getValue()));
String contentTypeValue = headers.getFirst(HttpHeaders.CONTENT_TYPE);
if (StringUtils.hasLength(contentTypeValue)) {
exchange.getAttributes().put(ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR, contentTypeValue);
}
setResponseStatus(res, response);
// make sure headers filters run after setting status so it is
// available in response
HttpHeaders filteredResponseHeaders = HttpHeadersFilter.filter(getHeadersFilters(), headers, exchange,
Type.RESPONSE);
if (!filteredResponseHeaders.containsKey(HttpHeaders.TRANSFER_ENCODING)
&& filteredResponseHeaders.containsKey(HttpHeaders.CONTENT_LENGTH)) {
// It is not valid to have both the transfer-encoding header and
// the content-length header.
// Remove the transfer-encoding header in the response if the
// content-length header is present.
response.getHeaders().remove(HttpHeaders.TRANSFER_ENCODING);
}
exchange.getAttributes().put(CLIENT_RESPONSE_HEADER_NAMES, filteredResponseHeaders.keySet());
response.getHeaders().addAll(filteredResponseHeaders);
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));
}