Nginx路径匹配规则详解

jopen 5年前

本节要讨论Nginx如何为一个请求选择匹配的location进行处理。

如下配置文件:

server {      listen         80 default_server;      server_name  itravel.smartcom.cc itravel-beta.huawei.com;      client_max_body_size  8M;      server_tokens  off;      root   /data/web/itravel2.smartcom.cc/trunk/htdocs;         error_page     404  /404.htm;      error_page    500 502 503 504  /50x.htm;         location / {          #root   /data/web/itravel2.smartcom.cc/trunk/htdocs;          index  index.php index.html index.htm;          if (!-e $request_filename) {              rewrite ^(.+)\.html$ $1.php last;          }      }         location /static/js/ {          #root /data/web/itravel2.smartcom.cc/trunk/htdocs;          concat on;          concat_types text/javascript;      }         location /static/css/ {          #root /data/web/itravel2.smartcom.cc/trunk/htdocs;          concat on;          concat_types text/css;      }         location /api { }         location ~/\.ht { }            location ~ ^/~([^/]+)(/?.*)$ { }         location ~ \.do$ { }         location ~ \.(jpg|jpeg|gif|png|ico|css|tgz|gz|bz2|pdf|txt|tar|bmp|js|mov) { }         location ~ /trip/ { }         location /trip/ { }         location ~ \.php$ { }   }

第一步:请求URI(路径)规范化。

所谓规范化,就是先将URI中形如“%XX”的编码字符进行解码,再解析URI中的相对路径“.”和“..”部分, 另外还可能会压缩相邻的两个或多个斜线成为一个斜线。

举例说明:若REQUEST_URI为//trip/t.php,则规范化后为/trip/t.php,Nginx将规范前的值存放在$request_uri中,而规范化后的值存放在$uri中。

其中,$request_uri和$uri为Nginx内嵌变量。

第二步:请求URI路径匹配。

首先需要明确Nginx中将路径匹配分为两类:

  1. 前缀路径匹配,即前缀字符串定义的路径,如上配置文件中“/,/static/js/,/static/css/,/api,/trip/”
    </li>
  2. 正则表达式路径匹配,即使用正则表达式需要在路径开始添加“~*”前缀 (不区分大小写),或者“~”前缀(区分大小写)。如上配置文件中“/\.ht,^/~([^/]+)(/?.*)$,\.do$,/trip/, \.php$,\.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|pdf|txt|tar||bmp|rtf|js|mov)”
  3. </ol> </div>

    其次为了根据请求URI查找路径,需要明确路径匹配的顺序:

    Nginx首先检查前缀字符串定义的路径 (前缀路径),在这些路径中找到能最精确匹配请求URI的路径。然后Nginx按在配置文件中的出现顺序检查正则表达式路径,匹配上某个路径后即停止匹配并使用该路径的配置,否则使用最大前缀匹配的路径的配置。

    举例说明:请求/trip/t.php,首先进行前缀路径匹配,最精确的前缀路径为/trip/,接下来进行正则表达式匹配,匹配到\.php$,从而进行location ~ \.php$ { }处理请求。反之若请求的是/trip/t.html,由于没有正则表达式匹配到该URI,故匹配最精确的前缀路径匹配,即进入location /trip/ { }处理请求。若想不论是请求/trip/t.php,还是/trip/t.html,都匹配到/trip/进行处理,则可以使用location ^~ /trip/ { },这样Nginx就不会再检查正则表达式了。

    备注:

    路径可以嵌套,但有例外。
    在不区分大小写的操作系统(诸如Mac OS X和Cygwin)上,前缀匹配忽略大小写(0.7.7)。但是,比较仅限于单字节的编码区域(one-byte locale)。
    正则表达式中可以包含匹配组(0.7.40),结果可以被后面的其他指令使用。
    如果最大前缀匹配的路径以“^~”开始,那么Nginx不再检查正则表达式。
    在0.7.1到0.8.41的所有Nginx中,如果请求匹配的前缀字符串路径并没有“=”或“^~”前缀, 路径查找过程仍然会停止,而不进行正则表达式匹配。
    </blockquote>

    而且,使用“=”前缀可以定义URI和路径的精确匹配。如果发现匹配,则终止路径查找。 比如,如果请求“/”出现频繁,定义“location = /”可以提高这些请求的处理速度, 因为查找过程在第一次比较以后即结束。这样的路径明显不可能包含嵌套路径。

    </div> </blockquote> </div>

    扩展阅读: