您好,登錄后才能下訂單哦!
這篇文章主要講解了“怎么配置nginx的反向代理”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“怎么配置nginx的反向代理”吧!
tomcat使用了nginx反向代理,獲取的服務(wù)器路徑變成了nginx中配置的內(nèi)網(wǎng)地址,如果在同一臺(tái)服務(wù)器上,就變成了127.0.0.1或是localhost,而我們需要的是外網(wǎng)地址,這時(shí)候我們需要啟用轉(zhuǎn)發(fā)的請(qǐng)求頭配置
如何啟用?下面通過查看源碼找一下如何解決
很多人都會(huì)強(qiáng)調(diào)看源碼,如果在沒有目的的情況下直接看源碼比較枯燥,很難堅(jiān)持(大神略過),不會(huì)有太大的收獲。如果我們遇到問題,很多時(shí)候都是網(wǎng)上一百度,配置項(xiàng)或是代碼復(fù)制粘貼,然后測(cè)試一下沒有問題就過了,但是如果網(wǎng)上的信息很少,或者幾乎找不到解決辦法,這時(shí)候,我們查看一下源碼,找到對(duì)應(yīng)實(shí)現(xiàn),有時(shí)候直接就能發(fā)現(xiàn)問題在哪,我認(rèn)為這種時(shí)候就是讀源碼的最好時(shí)機(jī),利用好eclipse或是intellij IDEA的搜索功能,一般都可以找到對(duì)應(yīng)的源碼
先來看一下spring boot tomcat源碼 TomcatWebServerFactoryCustomizer類
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); } }
可以看出,只要protocolHeader和remoteIpHeader任意一項(xiàng)有值就啟用了RemoteIpValve
spring boot 對(duì)應(yīng)配置項(xiàng)在Tomcat類里面:
server.use-forward-headers=true server.tomcat.remote-ip-header=x-forwarded-for server.tomcat.protocol-header=X-Forwarded-Proto
獲取服務(wù)器地址的實(shí)現(xiàn)在RemoteIpValve類的invoke方法里面
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); } } }
實(shí)現(xiàn)在大致過程是如果啟用RemoteIpValve,會(huì)去獲取指定的請(qǐng)求頭,更新RemoteAddr和Scheme的值,以及https轉(zhuǎn)的http服務(wù),secure表示是否是https服務(wù)
那么就需要在nginx中配置好我們服務(wù)的請(qǐng)求地址,也就是host請(qǐng)求頭
對(duì)應(yīng)nginx配置項(xiàng):
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;
這樣我們?cè)诤蠖朔?wù)中直接使用request.getRequestURL()方法就可以獲取到我們?cè)趎ginx中指定的服務(wù)器地址了,如果沒有使用nginx,就不存在該問題,所以后端服務(wù)不需要考慮服務(wù)是否使用了反向代理
感謝各位的閱讀,以上就是“怎么配置nginx的反向代理”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對(duì)怎么配置nginx的反向代理這一問題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。