关于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;
)

posted @ 2017-10-07 16:44  构建巨人肩膀  阅读(10143)  评论(0编辑  收藏  举报