關於NGINX利用location的匹配規則分流和利用server的server_name分流


一、前提:

nginx是可以利用server-->server_name和location的匹配規則進行分流的

 

二、分流1:利用location匹配url

1.nginx配置:

  

server {
        listen        80;
        server_name        x1.cc.com;
        
        location / {
            root   html;
            #index  index.html index.htm;
            index x1.html;
        }
        
        location ^~ /project1/ {
            #root   C:\\Users\\Administrator\\Desktop\\demo\\nginx-1.11.6\\html;
           
            #index /project1.html;
            proxy_pass http://127.0.0.1:8080;
        }
    }

2.tomcat9的配置

<?xml version="1.0" encoding="UTF-8"?>

<Server port="8005" shutdown="SHUTDOWN">
  <Listener className="org.apache.catalina.startup.VersionLoggerListener" />


  <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
 
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
  <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />

 
  <GlobalNamingResources>
   
    <Resource name="UserDatabase" auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml" />
  </GlobalNamingResources>

  
  <Service name="Catalina">

   
    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
    
    <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />


    <Engine name="Catalina" defaultHost="localhost">

      <Realm className="org.apache.catalina.realm.LockOutRealm">
   
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
               resourceName="UserDatabase"/>
      </Realm>

      <Host name="localhost"  appBase=""
            unpackWARs="true" autoDeploy="true">
            
            <Context path="/project1/" docBase="C:\Users\Administrator\Desktop\demo\qysxy-erp" reloadable="false"/>
            

      
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log" suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />

      </Host>
    </Engine>
  </Service>
</Server>

 

此時:x1.cc.com/*這個路徑會在nginx下處理,而x1.cc.com/project1/*整個URL就會交給被代理的服務器處理

出現的問題:

  1.由於在開發的時候,不會關注部署的情況,所以,“/project1/”這個URL前綴並不會被考慮到,如果web應用服務器是tomcat的話,就需要配置path:<Context path="/project1/" docBase="C:\Users\Administrator\Desktop\demo\{項目名稱}" reloadable="false"/>,這樣,一般的請求可以直接處理。但是記住,在開發的時候,如果涉及到重定向的時候,而且重定向的是本項目的服務,由於開發的時候沒有考慮到部署的url會有其他的前綴,所以,源代碼中的重定向不會加上這個URL前綴,此時會出現重定向失敗,(傻瓜式的解決辦法就是,在所有重定向中加上url前綴,造成開發上的麻煩)

 

總結:

1.不建議以url的方式進行分流,會造成后期的維護麻煩

 

三、分流2:利用域名的匹配來分流到不同的項目

windows下的實驗:
1.修改hosts文件,一般位於 C:\Windows\System32\drivers\etc

# Copyright (c) 1993-2009 Microsoft Corp.
#
# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.
#
# This file contains the mappings of IP addresses to host names. Each
# entry should be kept on an individual line. The IP address should
# be placed in the first column followed by the corresponding host name.
# The IP address and the host name should be separated by at least one
# space.
#
# Additionally, comments (such as these) may be inserted on individual
# lines or following the machine name denoted by a '#' symbol.
#
# For example:
#
#      102.54.94.97     rhino.acme.com          # source server
#       38.25.63.10     x.acme.com              # x client host

# localhost name resolution is handled within DNS itself.
#    127.0.0.1       localhost
#    ::1             localhost
    127.0.0.1        x1.cc.com
    127.0.0.1        x2.cc.com

2.nginx配置

server {
        listen        80;
        server_name        x1.cc.com;
        
        location / {
            root   html;
            #index  index.html index.htm;
            index x1.html;
        }
        
        
    }
    
    server {
        listen        80;
        server_name        x2.cc.com;
        
        location / {
            root   html;
            #index  index.html index.htm;
            index x2.html;
        }
    }

此時:即使是x1.cc.com和x2.cc.com綁定的是同一個IP,不通的域名訪問,也會進行不同的處理。

  例如:x1.cc.com/和x2.cc.com/訪問得到分別是x1.html和x2.html兩個文件

總結:

1、推薦這種做法,開發和部署兩個階段的url是互不影響的,不必相互考慮。但不足的是,需要兩個以上的域名,二級域名即可,所以不會造成太多麻煩

 

四、nginx+tomcat  搭建項目集群的簡單配置    

1.nginx配置

    upstream project {
        ip_hash;
        server 127.0.0.1:8080;
        server 127.0.0.1:8081;
        
    }
    
    server {
        listen        80;
        server_name        x1.cc.com;

    location / {
      proxy_set_header Host $host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Real-Port $remote_port;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_pass http://project;
    }


    }

注意:如果是nginx+tomcat,此時java程序中的獲取ip方法,request.getRemoteAddr()可能會出錯,用以下代碼獲取IP:

public static String getIpAddr(HttpServletRequest request) {
        String ipAddress = null;
        ipAddress = request.getHeader("x-forwarded-for");
        if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("Proxy-Client-IP");
        }

        if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("WL-Proxy-Client-IP");
        }

        if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getRemoteAddr();
            if(ipAddress.equals("127.0.0.1")) {
                InetAddress inet = null;

                try {
                    inet = InetAddress.getLocalHost();
                } catch (UnknownHostException var4) {
                    var4.printStackTrace();
                }

                ipAddress = inet.getHostAddress();
            }
        }

        if(ipAddress != null && ipAddress.length() > 15 && ipAddress.indexOf(",") > 0) {
            ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
        }

        return ipAddress;
    }

 

 

 

 

附錄:

一、location匹配規則:

location匹配命令

~      #波浪線表示執行一個正則匹配,區分大小寫
~*    #表示執行一個正則匹配,不區分大小寫
^~    #^~表示普通字符匹配,如果該選項匹配,只匹配該選項,不匹配別的選項,一般用來匹配目錄
=      #進行普通字符精確匹配
@     #"@" 定義一個命名的 location,使用在內部定向時,例如 error_page, try_files

 

location 匹配的優先級(與location在配置文件中的順序無關)
= 精確匹配會第一個被處理。如果發現精確匹配,nginx停止搜索其他匹配。
普通字符匹配,正則表達式規則和長的塊規則將被優先和查詢匹配,也就是說如果該項匹配還需去看有沒有正則表達式匹配和更長的匹配。
^~ 則只匹配該規則,nginx停止搜索其他匹配,否則nginx會繼續處理其他location指令。
最后匹配理帶有"~"和"~*"的指令,如果找到相應的匹配,則nginx停止搜索其他匹配;當沒有正則表達式或者沒有正則表達式被匹配的情況下,那么匹配程度最高的逐字匹配指令會被使用。

location 優先級官方文檔

  1. Directives with the = prefix that match the query exactly. If found, searching stops.
  2. All remaining directives with conventional strings, longest match first. If this match used the ^~ prefix, searching stops.
  3. Regular expressions, in order of definition in the configuration file.
  4. If #3 yielded a match, that result is used. Else the match from #2 is used.
  1. =前綴的指令嚴格匹配這個查詢。如果找到,停止搜索。
  2. 所有剩下的常規字符串,最長的匹配。如果這個匹配使用^〜前綴,搜索停止。
  3. 正則表達式,在配置文件中定義的順序。
  4. 如果第3條規則產生匹配的話,結果被使用。否則,使用第2條規則的結果。  

例如

location = / {
# 只匹配"/".
[ configuration A ]
}
location / {
# 匹配任何請求,因為所有請求都是以"/"開始
# 但是更長字符匹配或者正則表達式匹配會優先匹配
[ configuration B ]
}
location ^~ /images/ {
# 匹配任何以 /images/ 開始的請求,並停止匹配 其它location
[ configuration C ]
}
location ~* .(gif|jpg|jpeg)$ {
# 匹配以 gif, jpg, or jpeg結尾的請求.
# 但是所有 /images/ 目錄的請求將由 [Configuration C]處理.
[ configuration D ]
}

 

請求URI例子:

  • / -> 符合configuration A
  • /documents/document.html -> 符合configuration B
  • /images/1.gif -> 符合configuration C
  • /documents/1.jpg ->符合 configuration D

@location 例子
error_page 404 = @fetch;

location @fetch(
proxy_pass http://fetch;
)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM