Spring server.forward-headers-strategy NATIVE 与 FRAMEWORK

Aru*_*wda 30 java spring tomcat spring-hateoas spring-boot

我最近将 spring boot 从 1.x 升级到 2.y,并面临这个问题,其中 hatoas 链接是使用httpschema 而不是https.

后来我发现,在 spring boot 2.2+ 中,必须使用以下属性

server.forward-headers-strategy=NATIVE
Run Code Online (Sandbox Code Playgroud)

其中可以有NATIVEFRAMEWORK或 之一NONE

NONE属性非常简单,它完全禁用前向标头的使用。

NATIVE但是vs没有明确的文档FRAMEWORK。我在很多地方都看到提到NATIVE在大多数情况下效果最好。但没有解释当我们使用这些属性时幕后到底发生了什么。

这里的文档没有提供足够的信息让我在 Native/Framework 之间进行选择。它只说明谁处理相应值的转发标头。Servlet 容器?还是Spring框架?但这又回到了第 1 步。我应该让容器来处理它吗?或者框架?我什么时候应该选择其中一种而不是另一种?

我正在将 REST Web 应用程序与外部 tomcat 一起使用并Hateoas生成链接。

我如何决定是否使用 NATIVEFRAMEWORK财产?什么时候应该优先选择其中之一?为什么?

我的 springboot 版本:2.4.6

我已经尝试过的参考资料:

编辑:

我尝试了这两种解决方案并且framework对我有用,但native在外部 tomcat 环境中不起作用。我创建了一个新的 Spring Boot Web 应用程序,其中嵌入了 Tomcat,并且两者都native可以framework工作。

yej*_*lue 38

框架

FRAMEWORK使用 Spring 支持处理转发的标头。例如,Spring BootForwardedHeaderFilter在 时自动为 Spring MVC 创建一个 bean server.forward-headers-strategy=framework

@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;
}
Run Code Online (Sandbox Code Playgroud)

ForwardedHeaderFilter处理非标准标头X-Forwarded-HostX-Forwarded-PortX-Forwarded-ProtoX-Forwarded-SslX-Forwarded-Prefix

本国的

NATIVE使用底层容器对转发标头的本机支持。底层容器是指tomcat、jetty、netty等。例如,Spring Boot自动配置的嵌入式Tomcat处理非标准头X-Forwarded-Host, X-Forwarded-Port, X-Forwarded-Proto, X-Forwarded-Ssl,但不处理X-Forwarded-Prefix

X-转发前缀

例如,API 网关运行在 上localhost:8080,api 服务sga-booking运行在 上localhost:20000。API网关路由/sga-booking转发到api服务sga-booking。请求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
Run Code Online (Sandbox Code Playgroud)

ForwardedHeaderFilter处理包括 在内的转发标头时X-Forwarded-Prefix,生成的链接以 开头localhost:8080/sga-booking。如果X-Forwarded-Prefix不处理,生成的链接以 开头localhost:8080

Spring Boot 自动配置的嵌入式 Tomcat

使用 property server.forward-headers-strategy=native,方法 org.springframework.boot.autoconfigure.web.embedded.TomcatWebServerFactoryCustomizer#customizeRemoteIpValve可以配置RemoteIpValve属性server.tomcat.remoteip( org.springframework.boot.autoconfigure.web.ServerProperties.Tomcat.Remoteip) 来处理转发的标头。请注意,X-Forwarded-Prefix未处理。

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
Run Code Online (Sandbox Code Playgroud)

外部雄猫

// 抱歉,我从学校毕业后已经好几年没有玩过原版 Tomcat 了。以下 Tomcat 信息可能有误。
为了让外部Tomcat处理转发的标头,就像Spring Boot配置的那样,我认为ARemoteIpValve应该通过add来配置

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

到雄猫server.xml?或者context.xml在这里查找所有远程 ip 阀门属性。请注意,没有任何属性与 相关X-Forwarded-Prefix

Tomcat过滤器RemoteIpFilter可能有类似的功能。我不知道他们的区别。

参考