聊聊spring cloud gateway的RemoveHopByHopHeadersFilter

本文主要研究一下spring cloud gateway的RemoveHopByHopHeadersFilter

GatewayAutoConfiguration

spring-cloud-gateway-core-2.0.0.RC1-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 {
    //......
    @Bean
    public RemoveHopByHopHeadersFilter removeHopByHopHeadersFilter() {
        return new RemoveHopByHopHeadersFilter();
    }
    //......
}

可以看到这里自动new了一个RemoveHopByHopHeadersFilter

RemoveHopByHopHeadersFilter

spring-cloud-gateway-core-2.0.0.RC1-sources.jar!/org/springframework/cloud/gateway/filter/headers/RemoveHopByHopHeadersFilter.java

@ConfigurationProperties("spring.cloud.gateway.filter.remove-hop-by-hop")
public class RemoveHopByHopHeadersFilter implements HttpHeadersFilter, Ordered {

    public static final Set<String> HEADERS_REMOVED_ON_REQUEST =
            new HashSet<>(Arrays.asList(
                    "connection",
                    "keep-alive",
                    "transfer-encoding",
                    "te",
                    "trailer",
                    "proxy-authorization",
                    "proxy-authenticate",
                    "x-application-context",
                    "upgrade"
                    // these two are not listed in https://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-14#section-7.1.3
                    //"proxy-connection",
                    // "content-length",
                    ));

    private int order = Ordered.LOWEST_PRECEDENCE;

    private Set<String> headers = HEADERS_REMOVED_ON_REQUEST;

    public Set<String> getHeaders() {
        return headers;
    }

    public void setHeaders(Set<String> headers) {
        this.headers = headers;
    }

    @Override
    public int getOrder() {
        return order;
    }

    public void setOrder(int order) {
        this.order = order;
    }

    @Override
    public HttpHeaders filter(HttpHeaders input, ServerWebExchange exchange) {
        HttpHeaders filtered = new HttpHeaders();

        input.entrySet().stream()
                .filter(entry -> !this.headers.contains(entry.getKey().toLowerCase()))
                .forEach(entry -> filtered.addAll(entry.getKey(), entry.getValue()));

        return filtered;
    }

    @Override 
    public boolean supports(Type type) {
        return type.equals(Type.REQUEST) ||
                type.equals(Type.RESPONSE);
    }
}

可以看到这个filter是移除request或response中指定的header,默认移除的header包括”connection”,”keep-alive”, “transfer-encoding”,”te”,”trailer”,”proxy-authorization”,”proxy-authenticate”,”x-application-context”,”upgrade”。 也可以自己在配置文件指定要移除的header

配置

spring-cloud-gateway-core-2.0.0.RC1.jar!/META-INF/spring-configuration-metadata.json

    {
      "sourceType": "org.springframework.cloud.gateway.filter.headers.RemoveHopByHopHeadersFilter",
      "name": "spring.cloud.gateway.filter.remove-hop-by-hop.headers",
      "type": "java.util.Set<java.lang.String>"
    },
    {
      "sourceType": "org.springframework.cloud.gateway.filter.headers.RemoveHopByHopHeadersFilter",
      "name": "spring.cloud.gateway.filter.remove-hop-by-hop.order",
      "type": "java.lang.Integer"
    }

可以看到,有个order属性用来指定该filter的优先级,默认是Ordered.LOWEST_PRECEDENCE 还有另外一个属性headers,用来指定要移除的header

实例

spring:
  cloud:
    gateway:
      filter:
        remove-hop-by-hop:
          headers:
            - x-route
            - x-auth-id

使用

spring-cloud-gateway-core-2.0.0.RC1-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;
    }

    @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.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 response
            HttpHeaders 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 NettyWriteResponseFilter
            exchange.getAttributes().put(CLIENT_RESPONSE_ATTR, res);
        }).then(chain.filter(exchange));
    }
}

这里头对于request,调用的是

        HttpHeaders filtered = filterRequest(this.headersFilters.getIfAvailable(),
                exchange);

对于response调用的是

            HttpHeaders filteredResponseHeaders = HttpHeadersFilter.filter(
                    this.headersFilters.getIfAvailable(), headers, exchange, Type.RESPONSE);

小结

RemoveHopByHopHeadersFilter可以用来移除指定的header,其作用于request及response。

doc

  • 112.9 RemoveNonProxyHeaders GatewayFilter Factory

原文发布于微信公众号 - 码匠的流水账(geek_luandun)

原文发表时间:2018-05-30

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏微服务

微信小程序获取用户信息签名解密C#

在做小程序时,官方没有C#的解密,自己给写一个封装,希望可以帮到大家 #region 解密 #region 私有方法 ...

3989
来自专栏码匠的流水账

聊聊storm的IEventLogger

storm-2.0.0/storm-client/src/jvm/org/apache/storm/metric/IEventLogger.java

1403
来自专栏计算机视觉与深度学习基础

Leetcode 题目列表(难度、出现频率、知识点)

不全,但好像没看到有更好的版本,刷前132题暂时凑合着用吧! 转载自:LeetCode Question Difficulty Distribution ?...

4156
来自专栏Java学习网

Java实现把整数转换为英语单词的方法,实用代码

一个非负整数转换为英文单词表示。 例如: 123 -> "One Hundred Twenty Three" 12345 -> "Twelve Thousand...

2489
来自专栏GIS讲堂

Openlayers2卷帘功能的实现

在WebGIS开发中,经常会有用户提需求,要实现卷帘功能,卷帘功能主要是实现两张图之间的对比。在前文中,讲到了openlayers3以及Arcgis for j...

1602
来自专栏转载gongluck的CSDN博客

cocos2dx 连连看

#include "GameLink.h" #include "CountDownBar.h" USING_NS_CC; Scene* GameLink::...

3295
来自专栏码匠的流水账

聊聊kafka 0.8 ConsumerFetcherManager的MaxLag指标

本文主要研究一下kafka0.8.2.2版本中ConsumerFetcherManager的MaxLag指标的统计。

951
来自专栏码匠的流水账

聊聊spring cloud gateway的GlobalFilter

本文主要研究一下spring cloud gateway的GlobalFilter

1831
来自专栏Android知识点总结

看得见的数据结构Android版之双链表篇

671
来自专栏PPV课数据科学社区

【学习】七天搞定SAS(二):基本操作(判断、运算、基本函数)

? 今天开始注重变量操作。 SAS生成新变量 SAS支持基本的加减乘除,值得一提的是它的**代表指数,而不是^。* Modify homegarden dat...

4464

扫码关注云+社区

领取腾讯云代金券