溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

怎么配置nginx的反向代理

發(fā)布時(shí)間:2021-11-15 10:52:36 來源:億速云 閱讀:148 作者:iii 欄目:大數(shù)據(jù)

這篇文章主要講解了“怎么配置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)注!

向AI問一下細(xì)節(jié)

免責(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)容。

AI