tomcat uses the nginx reverse proxy, and the server path obtained becomes the intranet address configured in nginx. If on the same server, it becomes 127.0.0.1 or localhost. What we need is the extranet address. At this time, we need to enable the forwarding request header configuration.
How to enable it? Next, look at the source code to find out how to solve it.
Many people will emphasize to look at the source code, if there is no purpose to look directly at the source code is boring, it is difficult to adhere to (God skipped), there will not be much gain. If we encounter problems, most of the time is one hundred degrees online, configuration or code copy and paste, then test no problem, but if there is little information on the Internet, or almost no solution, at this time, we look at the source code, find the corresponding implementation, and sometimes find the problem directly, I think this time is the source of reading. Code the best time, make good use of the search function of eclipse or intellij IDEA, you can generally find the corresponding source code
Let's first look at the spring boot tomcat source code.
Tomcat WebServerFactoryCustomizer class
private void customizeRemoteIpValve(ConfigurableTomcatWebServerFactory factory) { Tomcat tomcatProperties = this.serverProperties.getTomcat(); String protocolHeader = tomcatProperties.getProtocolHeader(); String remoteIpHeader = tomcatProperties.getRemoteIpHeader(); // For back compatibility the valve is also enabled if protocol-header is set 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); } // The internal proxies default to a white list of "safe" internal IP // addresses valve.setInternalProxies(tomcatProperties.getInternalProxies()); valve.setPortHeader(tomcatProperties.getPortHeader()); valve.setProtocolHeaderHttpsValue( tomcatProperties.getProtocolHeaderHttpsValue()); // ... so it's safe to add this valve by default. factory.addEngineValves(valve); } }
As you can see, RemoteIpValve is enabled as long as either of the protocolHeader and remoteIpHeader has value
spring boot corresponds to the configuration item in the Tomcat class:
server.use-forward-headers=true server.tomcat.remote-ip-header=x-forwarded-for server.tomcat.protocol-header=X-Forwarded-Proto
The implementation of getting the server address is in the invoke method of the RemoteIpValve class
In general, if RemoteIpValve is enabled, the specified request header is obtained, the values of RemoteAddr and Scheme s are updated, and the http service transferred by https is represented by security.
Then we need to configure the request address of our service in nginx, which is the host request header.
Corresponding nginx configuration items:
proxy_set_header Host $host:$server_port; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Port $server_port; proxy_set_header X-Forwarded-Proto $scheme;
In this way, we can get the server address we specified in nginx by using the request. getRequest URL () method directly in the back-end service. If we do not use nginx, this problem will not exist, so the back-end service does not need to consider whether the service uses reverse proxy or not.
public void invoke(Request request, Response response) throws IOException, ServletException { final String originalRemoteAddr = request.getRemoteAddr(); final String originalRemoteHost = request.getRemoteHost(); final String originalScheme = request.getScheme(); final boolean originalSecure = request.isSecure(); final int originalServerPort = request.getServerPort(); final String originalProxiesHeader = request.getHeader(proxiesHeader); final String originalRemoteIpHeader = request.getHeader(remoteIpHeader); boolean isInternal = internalProxies != null && internalProxies.matcher(originalRemoteAddr).matches(); if (isInternal || (trustedProxies != null && trustedProxies.matcher(originalRemoteAddr).matches())) { String remoteIp = null; // In java 6, proxiesHeaderValue should be declared as a java.util.Deque LinkedList<String> proxiesHeaderValue = new LinkedList<>(); StringBuilder concatRemoteIpHeaderValue = new StringBuilder(); for (Enumeration<String> e = request.getHeaders(remoteIpHeader); e.hasMoreElements();) { if (concatRemoteIpHeaderValue.length() > 0) { concatRemoteIpHeaderValue.append(", "); } concatRemoteIpHeaderValue.append(e.nextElement()); } String[] remoteIpHeaderValue = commaDelimitedListToStringArray(concatRemoteIpHeaderValue.toString()); int idx; if (!isInternal) { proxiesHeaderValue.addFirst(originalRemoteAddr); } // loop on remoteIpHeaderValue to find the first trusted remote ip and to build the proxies chain for (idx = remoteIpHeaderValue.length - 1; idx >= 0; idx--) { String currentRemoteIp = remoteIpHeaderValue[idx]; remoteIp = currentRemoteIp; if (internalProxies !=null && internalProxies.matcher(currentRemoteIp).matches()) { // do nothing, internalProxies IPs are not appended to the } else if (trustedProxies != null && trustedProxies.matcher(currentRemoteIp).matches()) { proxiesHeaderValue.addFirst(currentRemoteIp); } else { idx--; // decrement idx because break statement doesn't do it break; } } // continue to loop on remoteIpHeaderValue to build the new value of the remoteIpHeader LinkedList<String> newRemoteIpHeaderValue = new LinkedList<>(); for (; idx >= 0; idx--) { String currentRemoteIp = remoteIpHeaderValue[idx]; newRemoteIpHeaderValue.addFirst(currentRemoteIp); } if (remoteIp != null) { request.setRemoteAddr(remoteIp); request.setRemoteHost(remoteIp); if (proxiesHeaderValue.size() == 0) { request.getCoyoteRequest().getMimeHeaders().removeHeader(proxiesHeader); } else { String commaDelimitedListOfProxies = listToCommaDelimitedString(proxiesHeaderValue); request.getCoyoteRequest().getMimeHeaders().setValue(proxiesHeader).setString(commaDelimitedListOfProxies); } if (newRemoteIpHeaderValue.size() == 0) { request.getCoyoteRequest().getMimeHeaders().removeHeader(remoteIpHeader); } else { String commaDelimitedRemoteIpHeaderValue = listToCommaDelimitedString(newRemoteIpHeaderValue); request.getCoyoteRequest().getMimeHeaders().setValue(remoteIpHeader).setString(commaDelimitedRemoteIpHeaderValue); } } if (protocolHeader != null) { String protocolHeaderValue = request.getHeader(protocolHeader); if (protocolHeaderValue == null) { // Don't modify the secure, scheme and serverPort attributes // of the request } else if (isForwardedProtoHeaderValueSecure(protocolHeaderValue)) { request.setSecure(true); request.getCoyoteRequest().scheme().setString("https"); setPorts(request, httpsServerPort); } else { request.setSecure(false); request.getCoyoteRequest().scheme().setString("http"); setPorts(request, httpServerPort); } } if (log.isDebugEnabled()) { log.debug("Incoming request " + request.getRequestURI() + " with originalRemoteAddr '" + originalRemoteAddr + "', originalRemoteHost='" + originalRemoteHost + "', originalSecure='" + originalSecure + "', originalScheme='" + originalScheme + "' will be seen as newRemoteAddr='" + request.getRemoteAddr() + "', newRemoteHost='" + request.getRemoteHost() + "', newScheme='" + request.getScheme() + "', newSecure='" + request.isSecure() + "'"); } } else { if (log.isDebugEnabled()) { log.debug("Skip RemoteIpValve for request " + request.getRequestURI() + " with originalRemoteAddr '" + request.getRemoteAddr() + "'"); } } if (requestAttributesEnabled) { request.setAttribute(AccessLog.REMOTE_ADDR_ATTRIBUTE, request.getRemoteAddr()); request.setAttribute(Globals.REMOTE_ADDR_ATTRIBUTE, request.getRemoteAddr()); request.setAttribute(AccessLog.REMOTE_HOST_ATTRIBUTE, request.getRemoteHost()); request.setAttribute(AccessLog.PROTOCOL_ATTRIBUTE, request.getProtocol()); request.setAttribute(AccessLog.SERVER_PORT_ATTRIBUTE, Integer.valueOf(request.getServerPort())); } try { getNext().invoke(request, response); } finally { request.setRemoteAddr(originalRemoteAddr); request.setRemoteHost(originalRemoteHost); request.setSecure(originalSecure); request.getCoyoteRequest().scheme().setString(originalScheme); request.setServerPort(originalServerPort); MimeHeaders headers = request.getCoyoteRequest().getMimeHeaders(); if (originalProxiesHeader == null || originalProxiesHeader.length() == 0) { headers.removeHeader(proxiesHeader); } else { headers.setValue(proxiesHeader).setString(originalProxiesHeader); } if (originalRemoteIpHeader == null || originalRemoteIpHeader.length() == 0) { headers.removeHeader(remoteIpHeader); } else { headers.setValue(remoteIpHeader).setString(originalRemoteIpHeader); } } }