简体   繁体   English

Spring server.forward-headers-strategy NATIVE vs FRAMEWORK

[英]Spring server.forward-headers-strategy NATIVE vs FRAMEWORK

I recently upgraded spring boot from 1.x to 2.y and was facing this issue where hateoas links were generated with http scheme instead of https .我最近将 spring boot 从 1.x 升级到 2.y 并面临这个问题,其中 hateoas 链接是使用http方案而不是https生成的。

Later I discovered that with spring boot 2.2+, it is mandatory to use the following property后来发现用spring boot 2.2+,强制使用如下属性

server.forward-headers-strategy=NATIVE

which can have one of NATIVE or FRAMEWORK or NONE .可以有NATIVEFRAMEWORKNONE

NONE property is pretty straight forward and it totally disables use of forward headers. NONE属性非常简单,它完全禁止使用前向标头。

But there is no clear documentation on NATIVE vs FRAMEWORK .但是没有关于NATIVEFRAMEWORK明确文档。 I've seen in many places it is mentioned that NATIVE works the best in most cases.我在很多地方都看到有人提到NATIVE在大多数情况下效果最好。 But there is no explanation on what exactly happens behind the scenes when we use these properties.但是当我们使用这些属性时,幕后到底发生了什么,并没有解释。

The documentation here doesn't give enough information for me to choose between Native/Framework. 此处文档没有提供足够的信息让我在 Native/Framework 之间进行选择。 All it says is who handles the forwarded headers for corresponding values.它所说的只是谁处理相应值的转发标头。 Servlet container? Servlet 容器? or Spring framework?还是Spring框架? but it brings back to square 1. Should I let container handle it?但它又回到了第 1 方格。我应该让容器处理它吗? or the framework?还是框架? when Should I prefer one over the other?什么时候我应该更喜欢一个?

I am using REST web application with external tomcat and Hateoas for generating the links.我正在使用带有外部 tomcat 和Hateoas REST Web 应用程序来生成链接。

How do I decide whether to use NATIVE or FRAMEWORK property?我如何决定是使用NATIVE还是FRAMEWORK属性? When should one be preferred over the other and why?什么时候应该优先选择另一个,为什么?

My springboot version: 2.4.6我的springboot版本: 2.4.6

References I've already tried:我已经尝试过的参考资料:

EDIT:编辑:

I tried both the solutions and framework works for me but not native in external tomcat environment.我尝试了对我有用的解决方案和framework ,但在外部 tomcat 环境中不是native I created a new spring boot web application with embedded tomcat and both native and framework works.我创建了一个带有嵌入式 tomcat 的新 Spring Boot Web 应用程序,并且nativeframework可以工作。

FRAMEWORK框架

FRAMEWORK uses Spring's support for handling forwarded headers. FRAMEWORK使用 Spring 的支持来处理转发的标头。 For example, Spring Boot auto creates an ForwardedHeaderFilter bean for Spring MVC when server.forward-headers-strategy=framework .例如,当server.forward-headers-strategy=framework时,Spring Boot 会自动为 Spring MVC 创建一个ForwardedHeaderFilter bean。

@Bean
@ConditionalOnMissingFilterBean(ForwardedHeaderFilter.class)
@ConditionalOnProperty(value = "server.forward-headers-strategy", havingValue = "framework")
public FilterRegistrationBean<ForwardedHeaderFilter> forwardedHeaderFilter() {
    ForwardedHeaderFilter filter = new ForwardedHeaderFilter();
    FilterRegistrationBean<ForwardedHeaderFilter> registration = new FilterRegistrationBean<>(filter);
    registration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ASYNC, DispatcherType.ERROR);
    registration.setOrder(Ordered.HIGHEST_PRECEDENCE);
    return registration;
}

ForwardedHeaderFilter handles non-standard headers X-Forwarded-Host , X-Forwarded-Port , X-Forwarded-Proto , X-Forwarded-Ssl , and X-Forwarded-Prefix . ForwardedHeaderFilter处理非标准标头X-Forwarded-HostX-Forwarded-PortX-Forwarded-ProtoX-Forwarded-SslX-Forwarded-Prefix

NATIVE本国的

NATIVE uses the underlying container's native support for forwarded headers. NATIVE使用底层容器对转发标头的本机支持。 The underlying container means tomcat, jetty, netty, etc. For example, the embedded Tomcat which is auto-configured by Spring Boot handles non-standard headers X-Forwarded-Host , X-Forwarded-Port , X-Forwarded-Proto , X-Forwarded-Ssl , but not X-Forwarded-Prefix .底层容器指的是tomcat、jetty、netty等,比如Spring Boot自动配置的内嵌Tomcat处理非标准headers X-Forwarded-Host , X-Forwarded-Port , X-Forwarded-Proto , X-Forwarded-Ssl ,但不是X-Forwarded-Prefix

X-Forwarded-Prefix X 转发前缀

For example, API gateway runs on localhost:8080 and api service sga-booking runs on localhost:20000 .例如,API 网关在localhost:8080上运行,而 api service sga-bookinglocalhost:20000上运行。 API gateway route /sga-booking is forwarded to api service sga-booking . API 网关路由/sga-booking被转发到 api 服务sga-booking The request to localhost:8080/sga-booking contains headers:localhost:8080/sga-booking的请求包含标题:

forwarded = proto=http;host="localhost:8080";for="0:0:0:0:0:0:0:1%0:46706"
x-forwarded-for = 0:0:0:0:0:0:0:1%0
x-forwarded-proto = http
x-forwarded-prefix = /sga-booking
x-forwarded-port = 8080
x-forwarded-host = localhost:8080
host = 192.168.31.200:20000

When ForwardedHeaderFilter handles forwarded headers including X-Forwarded-Prefix , generated links starts with localhost:8080/sga-booking .ForwardedHeaderFilter处理包括X-Forwarded-Prefix在内的转发标头时,生成的链接以localhost:8080/sga-booking开头。 If X-Forwarded-Prefix is not handled, generated links starts with localhost:8080 .如果未处理X-Forwarded-Prefix ,则生成的链接以localhost:8080开头。

Embedded Tomcat auto-configured by Spring Boot Spring Boot 自动配置的嵌入式 Tomcat

With property server.forward-headers-strategy=native , method org.springframework.boot.autoconfigure.web.embedded.TomcatWebServerFactoryCustomizer#customizeRemoteIpValve configures a RemoteIpValve with properties server.tomcat.remoteip ( org.springframework.boot.autoconfigure.web.ServerProperties.Tomcat.Remoteip ) to handle forwarded headers.使用属性server.forward-headers-strategy=native ,方法org.springframework.boot.autoconfigure.web.embedded.TomcatWebServerFactoryCustomizer#customizeRemoteIpValve使用属性server.tomcat.remoteiporg.springframework.boot.autoconfigure.web.ServerProperties.Tomcat.Remoteip配置RemoteIpValve org.springframework.boot.autoconfigure.web.ServerProperties.Tomcat.Remoteip ) 来处理转发的标头。 Note that X-Forwarded-Prefix is not handled.请注意,不处理X-Forwarded-Prefix

private void customizeRemoteIpValve(ConfigurableTomcatWebServerFactory factory) {
    Remoteip remoteIpProperties = this.serverProperties.getTomcat().getRemoteip();
    String protocolHeader = remoteIpProperties.getProtocolHeader();
    String remoteIpHeader = remoteIpProperties.getRemoteIpHeader();
    if (StringUtils.hasText(protocolHeader) || StringUtils.hasText(remoteIpHeader)
        || getOrDeduceUseForwardHeaders()) {
        RemoteIpValve valve = new RemoteIpValve();
        valve.setProtocolHeader(StringUtils.hasLength(protocolHeader) ? protocolHeader : "X-Forwarded-Proto");
        if (StringUtils.hasLength(remoteIpHeader)) {
            valve.setRemoteIpHeader(remoteIpHeader);
        }
        valve.setInternalProxies(remoteIpProperties.getInternalProxies());
        try {
            // X-Forwarded-Host by default
            valve.setHostHeader(remoteIpProperties.getHostHeader());
        }
        catch (NoSuchMethodError ex) {
            // Avoid failure with war deployments to Tomcat 8.5 before 8.5.44 and
            // Tomcat 9 before 9.0.23
        }
        // X-Forwarded-Port by default
        valve.setPortHeader(remoteIpProperties.getPortHeader());
        valve.setProtocolHeaderHttpsValue(remoteIpProperties.getProtocolHeaderHttpsValue());
        factory.addEngineValves(valve);
    }
}

External Tomcat外部Tomcat

// Sorry I haven't play vanilla Tomcat for years after graduating from school. // 抱歉,我毕业后好多年没有玩过香草 Tomcat。 Below Tomcat info may be wrong.以下Tomcat信息可能有误。
To make external Tomcat handle forwarded headers, like what Spring Boot configures, I think A RemoteIpValve should be configured by add为了让外部 Tomcat 处理转发的 headers,就像 Spring Boot 配置的那样,我认为应该通过 add 配置一个RemoteIpValve

<Context>
  ...
  <Valve className="org.apache.catalina.valves.RemoteIpValve" 
         hostHeader="X-Forwarded-Host"
         portHeader="X-Forwarded-Port"
       ...
  />
  ...
</Context>

to Tomcat server.xml ?到 Tomcat server.xml or context.xml ?context.xml Find all remote ip valve attributes here . 在此处查找所有远程 ip Valve 属性。 Note that no attribute is related to X-Forwarded-Prefix .请注意,没有任何属性与X-Forwarded-Prefix

Tomcat filter RemoteIpFilter may have similar function. Tomcat 过滤器RemoteIpFilter可能有类似的功能。 I don't know their difference.我不知道他们的区别。

Reference参考

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM