序
本文主要研究下spring cloud gateway的PreserveHostHeaderGatewayFilter
GatewayAutoConfiguration
spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java
@Configuration
@ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true)
@EnableConfigurationProperties
@AutoConfigureBefore(HttpHandlerAutoConfiguration.class)
@AutoConfigureAfter({GatewayLoadBalancerClientAutoConfiguration.class, GatewayClassPathWarningAutoConfiguration.class})
@ConditionalOnClass(DispatcherHandler.class)
public class GatewayAutoConfiguration {//......@Beanpublic PreserveHostHeaderGatewayFilterFactory preserveHostHeaderGatewayFilterFactory() {return new PreserveHostHeaderGatewayFilterFactory();}//......
}
复制代码
PreserveHostHeaderGatewayFilterFactory
spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java
public class PreserveHostHeaderGatewayFilterFactory extends AbstractGatewayFilterFactory {public GatewayFilter apply() {return apply(o -> {});}public GatewayFilter apply(Object config) {return (exchange, chain) -> {exchange.getAttributes().put(PRESERVE_HOST_HEADER_ATTRIBUTE, true);return chain.filter(exchange);};}
}
复制代码
这个filter超级简单,就往exchange添加PRESERVE_HOST_HEADER_ATTRIBUTE,设置为true
NettyRoutingFilter
spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/filter/NettyRoutingFilter.java
public class NettyRoutingFilter implements GlobalFilter, Ordered {private final HttpClient httpClient;private final ObjectProvider<List<HttpHeadersFilter>> headersFilters;public NettyRoutingFilter(HttpClient httpClient,ObjectProvider<List<HttpHeadersFilter>> headersFilters) {this.httpClient = httpClient;this.headersFilters = headersFilters;}@Overridepublic int getOrder() {return Ordered.LOWEST_PRECEDENCE;}@Overridepublic 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.getMethod().toString());final String url = requestUrl.toString();HttpHeaders filtered = filterRequest(this.headersFilters.getIfAvailable(),exchange);final DefaultHttpHeaders httpHeaders = new DefaultHttpHeaders();filtered.forEach(httpHeaders::set);String transferEncoding = request.getHeaders().getFirst(HttpHeaders.TRANSFER_ENCODING);boolean chunkedTransfer = "chunked".equalsIgnoreCase(transferEncoding);boolean preserveHost = exchange.getAttributeOrDefault(PRESERVE_HOST_HEADER_ATTRIBUTE, false);return this.httpClient.request(method, url, req -> {final HttpClientRequest proxyRequest = req.options(NettyPipeline.SendOptions::flushOnEach).headers(httpHeaders).chunkedTransfer(chunkedTransfer).failOnServerError(false).failOnClientError(false);if (preserveHost) {String host = request.getHeaders().getFirst(HttpHeaders.HOST);proxyRequest.header(HttpHeaders.HOST, host);}return proxyRequest.sendHeaders() //I shouldn't need this.send(request.getBody().map(dataBuffer ->((NettyDataBuffer)dataBuffer).getNativeBuffer()));}).doOnNext(res -> {ServerHttpResponse response = exchange.getResponse();// put headers and status so filters can modify the responseHttpHeaders headers = new HttpHeaders();res.responseHeaders().forEach(entry -> headers.add(entry.getKey(), entry.getValue()));HttpHeaders filteredResponseHeaders = HttpHeadersFilter.filter(this.headersFilters.getIfAvailable(), headers, exchange, Type.RESPONSE);response.getHeaders().putAll(filteredResponseHeaders);HttpStatus status = HttpStatus.resolve(res.status().code());if (status != null) {response.setStatusCode(status);} else if (response instanceof AbstractServerHttpResponse) {// https://jira.spring.io/browse/SPR-16748((AbstractServerHttpResponse) response).setStatusCodeValue(res.status().code());} else {throw new IllegalStateException("Unable to set status code on response: " +res.status().code()+", "+response.getClass());}// Defer committing the response until all route filters have run// Put client response as ServerWebExchange attribute and write response later NettyWriteResponseFilterexchange.getAttributes().put(CLIENT_RESPONSE_ATTR, res);}).then(chain.filter(exchange));}
}
复制代码
这里从读取PRESERVE_HOST_HEADER_ATTRIBUTE属性,没有则默认false。如果为true,则proxyRequest.header(HttpHeaders.HOST, host),传递host头部。
小结
PreserveHostHeaderGatewayFilter就是在gateway转发请求的时候把原始请求的host头部带上,转发给目标服务。默认该filter是启用的。
doc
- 112.6 PreserveHostHeader GatewayFilter Factory