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

查看:278
本文介绍了Spring server.forward-headers-strategy NATIVE vs FRAMEWORK的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

后来发现用spring boot 2.2+,强制使用如下属性

server.forward-headers-strategy=NATIVE

可以有 NATIVEFRAMEWORKNONE 之一.

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

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

此处的文档 没有提供足够的信息让我在本机/框架之间进行选择.它所说的只是谁处理相应值的转发标头.Servlet 容器?还是Spring框架?但它又回到了第 1 方格.我应该让容器处理它吗?还是框架?我什么时候应该更喜欢一个?

我正在使用带有外部 tomcat 和 Hateoas 的 REST 网络应用程序来生成链接.

我如何决定是使用 NATIVE 还是 FRAMEWORK 属性?什么时候应该优先选择另一个,为什么?

我的springboot版本:2.4.6

我已经尝试过的参考:

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

解决方案

FRAMEWORK

FRAMEWORK 使用 Spring 支持处理转发的标头.例如,当 server.forward-headers-strategy=framework.

时,Spring Boot 会自动为 Spring MVC 创建一个 ForwardedHeaderFilter bean.

@Bean@ConditionalOnMissingFilterBean(ForwardedHeaderFilter.class)@ConditionalOnProperty(value = "server.forward-headers-strategy", hasValue = "framework")public FilterRegistrationBeanforwardedHeaderFilter() {ForwardedHeaderFilter filter = new ForwardedHeaderFilter();FilterRegistrationBean注册 = 新的 FilterRegistrationBean<>(filter);registration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ASYNC, DispatcherType.ERROR);注册.setOrder(Ordered.HIGHEST_PRECEDENCE);退货登记;}

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

原生

NATIVE 使用底层容器对转发标头的本机支持.底层容器指的是tomcat、jetty、netty等,比如Spring Boot自动配置的内嵌Tomcat处理非标准headerX-Forwarded-HostX-Forwarded-PortX-Forwarded-ProtoX-Forwarded-Ssl,但不是 X-Forwarded-Prefix.>

X-Forwarded-Prefix

例如,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%0x-forwarded-proto = httpx-forwarded-prefix =/sga-bookingx 转发端口 = 8080x 转发主机 = 本地主机:8080主机 = 192.168.31.200:20000

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

Spring Boot 自动配置的嵌入式 Tomcat

使用属性server.forward-headers-strategy=native,方法org.springframework.boot.autoconfigure.web.embedded.TomcatWebServerFactoryCustomizer#customizeRemoteIpValve 使用属性 server.tomcat.remoteip (org.springframework.boot.autoconfigure.web.ServerProperties.Tomcat.Remoteip) 来处理转发的标头.注意 X-Forwarded-Prefix 没有被处理.

private void customRemoteIpValve(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 阀 = new RemoteIpValve();Valve.setProtocolHeader(StringUtils.hasLength(protocolHeader) ? protocolHeader : X-Forwarded-Proto");如果(StringUtils.hasLength(remoteIpHeader)){Valve.setRemoteIpHeader(remoteIpHeader);}Valve.setInternalProxies(remoteIpProperties.getInternalProxies());尝试 {//默认情况下 X-Forwarded-HostValve.setHostHeader(remoteIpProperties.getHostHeader());}抓住(NoSuchMethodError 前){//避免在 8.5.44 和 Tomcat 8.5 之前的 war 部署失败//9.0.23 之前的 Tomcat 9}//X-Forwarded-Port 默认Valve.setPortHeader(remoteIpProperties.getPortHeader());Valve.setProtocolHeaderHttpsValue(remoteIpProperties.getProtocolHeaderHttpsValue());factory.addEngineValves(阀门);}}

外部Tomcat

//抱歉,我毕业后好多年没玩过原版 Tomcat.以下Tomcat信息可能有误.
为了让外部 Tomcat 处理转发的 headers,就像 Spring Boot 配置的那样,我认为应该通过 add

配置一个 RemoteIpValve

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

到Tomcat server.xml?还是 context.xml?在此处查找所有远程 ip Valve 属性.请注意,没有任何属性与 X-Forwarded-Prefix 相关.

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

参考

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.

Later I discovered that with spring boot 2.2+, it is mandatory to use the following property

server.forward-headers-strategy=NATIVE

which can have one of NATIVE or FRAMEWORK or NONE.

NONE property is pretty straight forward and it totally disables use of forward headers.

But there is no clear documentation on NATIVE vs FRAMEWORK. I've seen in many places it is mentioned that NATIVE works the best in most cases. 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. All it says is who handles the forwarded headers for corresponding values. Servlet container? or Spring framework? but it brings back to square 1. Should I let container handle it? 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.

How do I decide whether to use NATIVE or FRAMEWORK property? When should one be preferred over the other and why?

My springboot version: 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. I created a new spring boot web application with embedded tomcat and both native and framework works.

解决方案

FRAMEWORK

FRAMEWORK uses Spring's support for handling forwarded headers. For example, Spring Boot auto creates an ForwardedHeaderFilter bean for Spring MVC when 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;
}

ForwardedHeaderFilter handles non-standard headers X-Forwarded-Host, X-Forwarded-Port, X-Forwarded-Proto, X-Forwarded-Ssl, and X-Forwarded-Prefix.

NATIVE

NATIVE uses the underlying container's native support for forwarded headers. 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.

X-Forwarded-Prefix

For example, API gateway runs on localhost:8080 and api service sga-booking runs on localhost:20000. API gateway route /sga-booking is forwarded to api service sga-booking. The request to localhost:8080/sga-booking contains headers:

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. If X-Forwarded-Prefix is not handled, generated links starts with localhost:8080.

Embedded Tomcat auto-configured by Spring Boot

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. Note that X-Forwarded-Prefix is not handled.

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

// Sorry I haven't play vanilla Tomcat for years after graduating from school. Below Tomcat info may be wrong.
To make external Tomcat handle forwarded headers, like what Spring Boot configures, I think A RemoteIpValve should be configured by add

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

to Tomcat server.xml? or context.xml? Find all remote ip valve attributes here. Note that no attribute is related to X-Forwarded-Prefix.

Tomcat filter RemoteIpFilter may have similar function. I don't know their difference.

Reference

这篇关于Spring server.forward-headers-strategy NATIVE vs FRAMEWORK的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆