关于nginx:nginx-location匹配和优先级

5次阅读

共计 2977 个字符,预计需要花费 8 分钟才能阅读完成。

一 语法和优先级

语法
location [= | ~ | ~* | ^~] uri {...}
location @name {...}

location 前面第一个参数是可选的。
=是准确匹配。当匹配到了,则完结。
^是正则匹配,辨别大小写。
^*是正则匹配,不辨别大小写。
^~是前缀匹配。

第一个参数不填,前面跟着 /uri。此时也是前缀匹配。只是优先级在正则匹配之后。
第一个参数不填,前面跟着 /。此时也是前缀匹配。只是优先级在所有匹配之后。也就是都匹配不到,则匹配该 location。
示例配置如下:

location /uri {# ...}
location / {# ...}

优先级:
当配置文件中有 =,优先匹配该 location,匹配到了,则完结匹配。匹配不到,则先找是否有^~
^~,则优先匹配该 location。匹配到了,则完结匹配。匹配不到,则依照配置文件程序,从上到下匹配。
先匹配第一个正则,匹配到了,则完结。
匹配不到,则往下匹配。
如果没有一个正则都匹配不到,则匹配/uri。有,则匹配该 location,而后完结。如果没有,则匹配/。有,则匹配该 location,而后完结。没有,则提醒 404。

所以把 = 放到第一个地位,能进步匹配速度。

另外,location 的所有匹配,都只对不带参数的申请的 uri 进行匹配的。
也就是 /test/test?a=1是一样的。

二 测试代码

1 准确匹配

拜访 http://localhost/test.png,因为有=,所以优先匹配,而后完结。

// 输入 4
server {
    listen       80;
    server_name  localhost;
    location ^~ /test.png {
        add_header Content-Type 'text/html;charset=utf-8';
        return 200 1;
    }
    location ~ /test.png {
        add_header Content-Type 'text/html;charset=utf-8';
        return 200 2;
    }
    location ~* /test.png  {
        add_header Content-Type 'text/html;charset=utf-8';
        return 200 3;
    }
    location = /test.png {
        add_header Content-Type 'text/html;charset=utf-8';
        return 200 4;
    }
}

2 前缀匹配

^~: 优先前缀匹配
/: 前缀匹配

最长匹配:指的是前缀匹配/,当有多个匹配的时候,先记住以后匹配,持续往下匹配,如果没有正则和优先前缀匹配,则始终匹配到最初一个 location,而后应用最长匹配到的 location。

拜访 http://localhost/test/txt/tt,匹配到第一个后,持续往下匹配。因为没有其余正则和优先前缀匹配,所以始终到第三个匹配,匹配到了,则完结。没匹配到,则以下面匹配的为准。
当拜访 http://localhost/test/txt/,则会把三个 location 都匹配完,才抉择最长匹配到的 location。
所以,如果应用 / 前缀匹配的时候,绝对会慢一些。

server {
    listen       80;
    server_name  localhost;
    location /test/ {
        add_header Content-Type 'text/html;charset=utf-8';
        return 200 1;
    }
    location /test/txt/ {
        add_header Content-Type 'text/html;charset=utf-8';
        return 200 2;
    }
    location /test/txt/t {
        add_header Content-Type 'text/html;charset=utf-8';
        return 200 3;
    }
}

/ 前缀匹配上面有优先前缀匹配或者正则,匹配到了,则完结。
当拜访http://localhost/test/txt/,到第二个 location 后,则完结匹配。

// 输入 2
server {
    listen       80;
    server_name  localhost;
    location /test/ {
        add_header Content-Type 'text/html;charset=utf-8';
        return 200 1;
    }
    location ^~ /test/txt/ {
        add_header Content-Type 'text/html;charset=utf-8';
        return 200 2;
    }
}

当拜访http://localhost/test/,匹配到正则后,则完结匹配。不会再往下匹配第三个 location。

// 输入 2
server {
    listen       80;
    server_name  localhost;
    location /test/ {
        add_header Content-Type 'text/html;charset=utf-8';
        return 200 1;
    }
    location ~ /test/ {
        add_header Content-Type 'text/html;charset=utf-8';
        return 200 2;
    }
    location ~ /test/txt/ {
        add_header Content-Type 'text/html;charset=utf-8';
        return 200 3;
    }
}

优先匹配 ^~ 跟在配置文件的程序无关。以下两种状况后果是一样的。
当拜访 http://localhost/test.png,都输入 1

// demo1
server {
    listen       80;
    server_name  localhost;
    location ^~ /test.png {
        add_header Content-Type 'text/html;charset=utf-8';
        return 200 1;
    }
    location ~ /test.png  {
        add_header Content-Type 'text/html;charset=utf-8';
        return 200 2;
    }
}
// demo2
server {
    listen       80;
    server_name  localhost;
    location ~ /test.png {
        add_header Content-Type 'text/html;charset=utf-8';
        return 200 2;
    }
    location ^~ /test.png {
        add_header Content-Type 'text/html;charset=utf-8';
        return 200 1;
    }
}

3 正则匹配

正则匹配,从上到下,匹配到了,则完结。
拜访 http://localhost/test.png,因为匹配到了第一个正则,所以就完结了。页面输入 2

server {
    listen       80;
    server_name  localhost;
    location ~ /test.png {
        add_header Content-Type 'text/html;charset=utf-8';
        return 200 2;
    }
    location ~ /test.png  {
        add_header Content-Type 'text/html;charset=utf-8';
        return 200 3;
    }
    location ~ /test.png {
        add_header Content-Type 'text/html;charset=utf-8';
        return 200 4;
    }
}
正文完
 0