赞
赏
Nginx 中的 location 指令是 nginx 中最关键的指令之一,location 指令的功能是用来匹配不同的 URI 请求,进而对请求做不同的处理和响应,这其中较难理解的是多个 location 的匹配顺序。
开始之前先明确一些约定,我们输入的网址叫做请求 URI,nginx 用请求 URI 与 location 中配置的 URI 做匹配。
location [ = | ~ | ~* | ^~ ] /URI { … } location @/name/ { … }
使用环境
server
说明
Location 块通过指定模式来与客户端请求的 URI 相匹配。匹配 URI 类型,有四种参数可选,当然也可以不带参数。
命名 location,用 @ 来标识,类似于定义 goto 语句块。
命令解释
参数 解释 空 location 后没有参数直接跟着标准 URI,表示前缀匹配,代表跟请求中的 URI 从头开始匹配。 = 用于标准 URI 前,要求请求字符串与其精准匹配,成功则立即处理,nginx 停止搜索其他匹配。 ^~ 用于标准 URI 前,并要求一旦匹配到就会立即处理,不再去匹配其他的那些个正则 URI,一般用来匹配目录 ~ 用于正则 URI 前,表示 URI 包含正则表达式, 区分大小写 ~* 用于正则 URI 前, 表示 URI 包含正则表达式, 不区分大小写 @ @ 定义一个命名的 location,@ 定义的 locaiton 名字一般用在内部定向,例如 error_page, try_files 命令中。它的功能类似于编程中的 goto。 匹配规则说明
模式 含义 location = /uri = 表示精确匹配,只有完全匹配上才能生效 location ^~ /uri ^~ 开头对 URL 路径进行前缀匹配,并且在正则之前 location ~ pattern 开头表示区分大小写的正则匹配 location ~* pattern 开头表示不区分大小写的正则匹配 location /uri 不带任何修饰符,也表示前缀匹配,但是在正则匹配之后 location / 通用匹配,任何未匹配到其它 location 的请求都会匹配到,相当于 switch 中的 default Nginx location匹配顺序
Nginx 有两层指令来匹配请求 URI 。第一个层次是 server 指令,它通过域名、ip 和端口来做第一层级匹配,当找到匹配的 server 后就进入此 server 的 location 匹配。
location 的匹配并不完全按照其在配置文件中出现的顺序来匹配,请求URI 会按如下规则进行匹配:
- 先精准匹配 = ,精准匹配成功则会立即停止其他类型匹配;
- 没有精准匹配成功时,进行前缀匹配。先查找带有 ^~ 的前缀匹配,带有 ^~ 的前缀匹配成功则立即停止其他类型匹配,普通前缀匹配(不带参数 ^~ )成功则会暂存,继续查找正则匹配;
- = 和 ^~ 均未匹配成功前提下,查找正则匹配 ~ 和 ~* 。当同时有多个正则匹配时,按其在配置文件中出现的先后顺序优先匹配,命中则立即停止其他类型匹配;
- 所有正则匹配均未成功时,返回步骤 2 中暂存的普通前缀匹配(不带参数 ^~ )结果。
以上规则简单总结就是优先级从高到低依次为(序号越小优先级越高):
1. location = # 精准匹配 2. location ^~ # 带参前缀匹配 3. location ~ # 正则匹配(区分大小写) 4. location ~* # 正则匹配(不区分大小写) 5. location /a # 普通前缀匹配,优先级低于带参数前缀匹配。 6. location / # 任何没有匹配成功的,都会匹配这里处理
location URI结尾带不带/
关于 URI 尾部的
/
有三点也需要说明一下。第一点与 location 配置有关,其他两点无关。
- location 中的字符有没有
/
都没有影响。也就是说/user/
和/user
是一样的。- 如果 URI 结构是
https://domain.com/
的形式,尾部有没有/
都不会造成重定向。因为浏览器在发起请求的时候,默认加上了/
。虽然很多浏览器在地址栏里也不会显示/
。- 如果 URI 的结构是
https://domain.com/some-dir/
。尾部如果缺少/
将导致重定向。因为根据约定,URL 尾部的/
表示目录,没有/
表示文件。所以访问/some-dir/
时,服务器会自动去该目录下找对应的默认文件。如果访问/some-dir
的话,服务器会先去找some-dir
文件,找不到的话会将some-dir
当成目录,重定向到/some-dir/
,去该目录下找默认文件。可以去测试一下你的网站是不是这样的。命名location
带有 @ 的 location 是用来定义一个命名的 location,这种 location 不参与请求匹配,一般用在内部定向。用法如下:
location / { try_files $uri $uri/ @custom } location @custom { # ...do something }
上例中,当尝试访问 URI 找不到对应的文件就重定向到我们自定义的命名 location(此处为 custom)。值得注意的是,命名 location 中不能再嵌套其它的命名 location。
案例
案例一
我们首选使用 vim 打开 nginx 的默认配置路径,具体命令如下:
vim /etc/nginx/conf.d/default.conf
我们执行如上命令,打开配置文件,接着,我们在 server 下面增加两个 location 配置,具体配置如下:
location /doc { return 701; # 用这样的方式,可以方便的知道请求到了哪里 } location ~* ^/document$ { return 702; }
配置完毕后,如下图所示:
现在,我们重新加载配置文件,具体命令如下:
nginx -s reload
重新加载配置后,我们使用 curl 测试,具体命令如下:
curl -I 127.0.0.1/document
执行完毕后,终端输出如下:
即,这里,优先匹配了下面的 document 配置。
案例二
我们在 Nginx 的 server 下面增加两个 location 配置,具体配置如下:
location /document { return 701;}location ~* ^/document$ { return 702;}
配置完毕后,如下图所示:
现在,我们重新加载配置文件,具体命令如下:
nginx -s reload
重新加载配置后,我们使用 curl 测试,具体命令如下:
curl -I 127.0.0.1/document
执行完毕后,终端输出如下:
即,这里,优先匹配了下面的 document 配置。
案例三
我们在 Nginx 的 server 下面增加两个 location 配置,具体配置如下:
location ^~ /doc { return 701;}location ~* ^/document$ { return 702;}
配置完毕后,如下图所示:
现在,我们重新加载配置文件,具体命令如下:
nginx -s reload
重新加载配置后,我们使用 curl 测试,具体命令如下:
curl -I 127.0.0.1/document
执行完毕后,终端输出如下:
即,这里,第一个前缀匹配 ^~ 命中以后不会再搜寻正则匹配,所以会第一个命中。
案例四
我们在 Nginx 的 server 下面增加两个 location 配置,具体配置如下:
location /docu { return 701;}location /doc { return 702;}
配置完毕后,如下图所示:
现在,我们重新加载配置文件,具体命令如下:
nginx -s reload
重新加载配置后,我们使用 curl 测试,具体命令如下:
curl -I 127.0.0.1/document
执行完毕后,终端输出如下:
这里,即使改变 701 配置和 702 配置的顺序,也一样首先匹配到 701,说明前缀匹配下,返回最长匹配的 location,与 location 所在位置顺序无关。
案例五
我们在 Nginx 的 server 下面增加两个 location 配置,具体配置如下:
location ~ ^/doc[a-z]+ { return 701;}location ~ ^/docu[a-z]+ { return 702;}
配置完毕后,如下图所示:
现在,我们重新加载配置文件,具体命令如下:
nginx -s reload
重新加载配置后,我们使用 curl 测试,具体命令如下:
curl -I 127.0.0.1/document
执行完毕后,终端输出如下:
现在,我们调换下 701 和 702 的顺序,修改如下:
location ~ ^/docu[a-z]+ { return 702;}location ~ ^/doc[a-z]+ { return 701;}
配置完毕后,如下图所示:
现在,我们重新加载配置文件,具体命令如下:
nginx -s reload
重新加载配置后,我们使用 curl 测试,具体命令如下:
curl -I 127.0.0.1/document
执行完毕后,终端输出如下:
可见正则匹配是使用文件中的顺序,先匹配成功的返回。
location使用建议
所以实际使用中,个人觉得至少有三个匹配规则定义,如下:
直接匹配网站根,通过域名访问网站首页比较频繁,使用这个会加速处理,官网如是说。
这里是直接转发给后端应用服务器了,也可以是一个静态首页。第一个必选规则:
location = / { proxy_pass http://tomcat:8080/index}
第二个必选规则是处理静态文件请求,这是 nginx 作为 http 服务器的强项,有两种配置模式,目录匹配或后缀匹配,任选其一或搭配使用:
location ^~ /static/ { root /webroot/static/;}location ~* \.(gif|jpg|jpeg|png|css|js|ico)$ { root /webroot/res/;}
第三个规则就是通用规则,用来转发动态请求到后端应用服务器,非静态文件请求就默认是动态请求,自己根据实际把握,毕竟目前的一些框架的流行,带 .php, .jsp 后缀的情况很少了:
![]()