序言

location 指令是 nginx 中最关键的指令之一,location 指令的功能是用来匹配不同的 URI 要求,进而对要求做不同的处理和相应,这个中较难明得的是多个 location 的匹配顺序,本文会作为重点来阐明息争释。

开始之前先明确一些约定,我们输入的网址叫做要求 URI,nginx 用要求 URI 与 location 中配置的 URI 做匹配。

nginx文件构造

首先我们先大略理解 nginx 的文件构造,nginx 的 HTTP 配置紧张包括三个区块,构造如下:

pluslistphptid一文理清 nginx 中的 location 设置装备摆设系列一 jQuery

Global: nginx 运行干系Events: 与用户的网络连接干系http http Global: 代理,缓存,日志,以及第三方模块的配置 server server Global: 虚拟主机干系 location: 地址定向,数据缓存,应答掌握,以及第三方模块的配置

从上面展示的 nginx 构造中可以看出 location 属于要求级别配置,这也是我们最常用的配置。

配置 location 块location 语法

Location 块通过指定模式来与客户端要求的URI相匹配。
Location基本语法:

匹配 URI 类型,有四种参数可选,当然也可以不带参数。
命名location,用@来标识,类似于定义goto语句块。

location [ = | ~ | ~ | ^~ ] /URI { … }location @/name/ { … }location匹配命令阐明

location匹配顺序

nginx有两层指令来匹配要求 URI 。
第一个层次是 server 指令,它通过域名、ip 和端口来做第一层级匹配,当找到匹配的 server 后就进入此 server 的 location 匹配。

location 的匹配并不完备按照其在配置文件中涌现的顺序来匹配,要求URI 会按如下规则进行匹配:

先精准匹配 = ,精准匹配成功则会立即停滞其他类型匹配;没有精准匹配成功时,进行前缀匹配。
先查找带有 ^~ 的前缀匹配,带有 ^~ 的前缀匹配成功则立即停滞其他类型匹配,普通前缀匹配(不带参数 ^~ )成功则会暂存,连续查找正则匹配;= 和 ^~ 均未匹配成功条件下,查找正则匹配 ~ 和 ~ 。
当同时有多个正则匹配时,按其在配置文件中涌现的先后顺序优先匹配,命中则立即停滞其他类型匹配;所有正则匹配均未成功时,返回步骤 2 中暂存的普通前缀匹配(不带参数 ^~ )结果

以上规则大略总结便是优先级从高到低依次为(序号越小优先级越高):

1. location = # 精准匹配2. location ^~ # 带参前缀匹配3. location ~ # 正则匹配(区分大小写)4. location ~ # 正则匹配(不区分大小写)5. location /a # 普通前缀匹配,优先级低于带参数前缀匹配。
6. location / # 任何没有匹配成功的,都会匹配这里处理

上述匹配规则可以用以下伪代码表示,加深理解:

function match(uri): rv = NULL if uri in exact_match: return exact_match[uri] if uri in prefix_match: if prefix_match[uri] is '^~': return prefix_match[uri] else: rv = prefix_match[uri] // 把稳这里没有 return,且这里是最长匹配 if uri in regex_match: return regex_match[uri] // 按文件中顺序,找到即返回 return rv案例剖析

接下来,让我们通过一些实际案例来验证上述规则。

案例 1

server { server_name website.com; location /doc { return 701; # 用这样的办法,可以方便的知道要求到了哪里 } location ~ ^/document$ { return 702; }}

curl -I website.com:8080/document 返回 返回 HTTP/1.1 702

解释:按照上述的规则,显然第二个正则匹配会有更高的优先级

案例 2

server { server_name website.com; location /document { return 701; } location ~ ^/document$ { return 702; }}

curl -I website.com:8080/document 返回 HTTP/1.1 702

解释:第二个匹配了正则表达式,优先级高于第一个普通前缀匹配

案例 3

server { server_name website.com; location ^~ /doc { return 701; } location ~ ^/document$ { return 702; }}

curl http://website.com/document 返回 HTTP/1.1 701

解释:第一个前缀匹配 ^~ 命中往后不会再征采正则匹配,以是会第一个命中。

案例 4

server { server_name website.com; location /docu { return 701; } location /doc { return 702; }}

curl -I website.com:8080/document 会返回 HTTP/1.1 701

server { server_name website.com; location /doc { return 702; } location /docu { return 701; }}

curl -I website.com:8080/document 依然返回 HTTP/1.1 701

解释:前缀匹配下,返回最长匹配的 location,与 location 所在位置顺序无关

案例 5

server { listen 8080; server_name website.com; location ~ ^/doc[a-z]+ { return 701; } location ~ ^/docu[a-z]+ { return 702; }}

curl -I website.com:8080/document 返回 HTTP/1.1 701

把顺序换一下

server { listen 8080; server_name website.com; location ~ ^/docu[a-z]+ { return 702; } location ~ ^/doc[a-z]+ { return 701; }}

curl -I website.com:8080/document 返回 HTTP/1.1 702

解释:可见正则匹配是利用文件中的顺序,先匹配成功的返回。

案例 6

末了我们对一个官方文档中提到例子做一些补充,来看一个相对较完全的例子,假设我们有如下几个要求等待匹配:

//index.html/documents/document.html/documents/abc/images/a.gif/documents/a.jpg

以下是 location 配置及其匹配情形

location = / { # 只精准匹配 / 的查询. [ configuration A ] }# 匹配成功: / location / { # 匹配任何要求,由于所有要求都因此”/“开始 # 但是更长字符匹配或者正则表达式匹配会优先匹配 [ configuration B ] }#匹配成功:/index.htmllocation /documents { # 匹配任何以 /documents/ 开头的地址,匹配符合往后,还要连续往下搜索/ # 只有后面的正则表达式没有匹配到时,这一条才会采取这一条/ [ configuration C ] }# 匹配成功:/documents/document.html# 匹配成功:/documents/abclocation ~ /documents/ABC { # 区分大小写的正则匹配 # 匹配任何以 /documents/ 开头的地址,匹配符合往后,还要连续往下搜索/ # 只有后面的正则表达式没有匹配到时,这一条才会采取这一条/ [ configuration CC ] }location ^~ /images/ { # 匹配任何以 /images/ 开头的地址,匹配符合往后,立即停滞往下搜索正则,采取这一条。
/ [ configuration D ] }# 成功匹配:/images/a.giflocation ~ \.(gif|jpg|jpeg)$ { # 匹配所有以 .gif、.jpg 或 .jpeg 结尾的要求,不区分大小写 # 然而,所有要求 /images/ 下的图片会被 [ config D ] 处理,由于 ^~ 到达不了这一条正则/ [ configuration E ] }# 成功匹配:/documents/a.jpglocation /images/ { # 字符匹配到 /images/,连续往下,会创造 ^~ 存在/ [ configuration F ] }location /images/abc { # 最长字符匹配到 /images/abc,连续往下,会创造 ^~ 存在/ # F与G的放置顺序是没有关系的/ [ configuration G ] }location ~ /images/abc/ { # 只有去掉 [ config D ] 才有效:先最长匹配 [ config G ] 开头的地址,连续往下搜索,匹配到这一条正则,采取/ [ configuration H ] }
其他location配置干系匹配问号后的参数

要求 URI 中问号后面的参数是不能在 location 中匹配到的,这些参数存储在 $query_string 变量中,可以用 if 来判断。
例如,对付参数中带有单引号 ’ 进行匹配然后重定向到缺点页面。

/plus/list.php?tid=19&mid=1124‘if ( $query_string ~ “.[;’<>].” ){ return 404;}location URI结尾带不带 /

关于 URI 尾部的 / 有三点也须要解释一下。
第一点与 location 配置有关,其他两点无关。

location 中的字符有没有 / 都没有影响。
也便是说 /user/ 和 /user 是一样的。
如果 URI 构造是 https://domain.com/ 的形式,尾部有没有 / 都不会造成重定向。
由于浏览器在发起要求的时候,默认加上了 / 。
虽然很多浏览器在地址栏里也不会显示 / 。
这一点,可以访问baidu验证一下。
如果 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。

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后缀的情形很少了:

location / { proxy_pass http://tomcat:8080/}结语

如果你以为看完本文后有所收成,劳烦 点赞 、 收藏 和 关注 哈,你的支持是我坚持分享的最大动力!