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
.
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