location 是 nginx 配置中出现最频繁的配置项,一个 uri 是如何与多个 location 进行匹配的?

在有多个 location 都匹配的情况下,如何决定使用哪一个 location 作为匹配结果?

清晰内部机制之后,疑问自然迎刃而解。

location 规则类型

根据官方文档,location 配置语法如下

Syntax:   location [ = | ~ | ~* | ^~ ] uri { ... }
location @name { ... }
Default: —
Context: server, location

其语法对应了 location 规则的 5 种类型:

prefix

前缀匹配规则,如果 uri 包含相应的前缀,则匹配成功。

语法上, location 之后单纯跟上 uri,没有任何操作符。

location /api/v1 {
....
}

exact uri

完全匹配规则,如果 uri 和规则完全相同,则匹配成功。

语法上,使用 = 操作符。

location = /api/v1 {
....
}

case-sensitive regex

区分大小写的正则表达式匹配规则,如果 uri 与正则表达式相匹配,则匹配成功。

正则表达式使用 pcre library,语法和 perl 兼容。

语法上,使用 ~ 操作符。

这里有一个细节,uri 作为一个 string,只要 regex 匹配其中的一部分,即可算作匹配。

比如有如下的规则,

location ~ /api/v1 {
....
}

可以匹配 uri

  • /api/v1/login
  • /pod/api/v1

如果想要匹配整个 string,则要使用 ^ $

比如,

location ~ ^/api/v1.*$ {
....
}

可以匹配 uri

  • /api/v1/login

不可以匹配

  • /pod/api/v1

case-insensitive regex

规则同上,区别只在于,正则表达式不区分大小写。

区分大小写的正则表达式匹配规则,如果 uri 与正则表达式相匹配,则匹配成功。

语法上,使用 ~* 操作符。

location ~* /api/v1 {
....
}

disable regex prefix

匹配流程与 prefix 规则相同,有一点区别在于,如果最长匹配是当前规则,则之后不进行 正则表达式 规则的搜索。

这一点可能有些难以理解,后面会详细讲解。

语法上,使用 ^~ 操作符。

location ^~ /api/v1 {
....
}

uri 如何选择 location

前面讲到,location 规则有 5 种类型,那么 uri 如何在多种不同类型的 location 规则之间,

最终选择到唯一的 location 规则呢?

根据官方文档的描述,详细规则如下:

  1. 如果存在 exact uri 规则与 uri 匹配,至步骤 6
  2. 在所有 prefix 规则和 disable regex prefix 规则中进行匹配(与这些规则定义的顺序无关),

    如果没有匹配到规则,至步骤 3;如果存在匹配的规则,选择出最长匹配 uri 的规则:

    • 如果规则是 disable regex prefix 类型,至步骤 6
    • 如果规则是 prefix 类型,记住当前匹配的 prefix 规则,选为待定,至步骤 3
  3. 逐个遍历 case-sensitive regex 规则和 case-insensitive regex 规则(按照这些规则定义的前后顺序):
    • 如果规则匹配,则遍历终止,至步骤 6
    • 如果规则没有匹配,则继续
  4. 如果之前有 prefix 规则条目被选择为待定,至步骤 6
  5. 匹配失败,返回404,结束
  6. 选择当前规则,使用其配置,结束

图解

draw by draw.io, 源文件

FAQ

有人可能会困惑,如果 prefix 与 disable regex prefix 规则相同,比如,

location /static/ {
....
}
location ^~ /static/ {
....
}

最终会匹配哪一条规则?是否应该继续查找 regex 规则?

实际上,这种情况 nginx 会报错,nginx: [emerg] duplicate location "/static/" in /etc/nginx/conf.d/location.conf

所以这种情况是不用考虑的。

示例

示例项目在 nginx example

参考 readme 文件,在本地启动 nginx server。

其中对 nginx 的配置如下,使用 curl 进行检测。

exact uri 规则先于所有规则(与规则定义的顺序无关),所以这里匹配了 = / exact uri 规则而不是 / prefix 规则。

$ curl http://localhost:8080/
uri "/": exact match "location = /"

exact uri 规则先于所有规则(与规则定义的顺序无关),所以这里没有匹配 ^~ /static/ disable regex prefix 和 ~* \.PNG$~ \.png$ regex 规则。

正是因为 exact uri 规则的这种属性,如果有高频率使用的 uri,建议使用 exact uri 匹配,加快匹配速度。

$ curl http://localhost:8080/static/logo.png
uri "/static/logo.png": exact uri match "location = /static/logo.png"

prefix 规则中,匹配 uri 长度最长的规则会选中,所以没有选中 / prefix 规则。同样的,从这一点来看,/api/api/ 是不一样的。

$ curl http://localhost:8080/api
uri "/api": prefix match "location /api"
$ curl http://localhost:8080/api/
uri "/api/": prefix match "location /api/"
$ curl http://localhost:8080/api/v1
uri "/api/v1": prefix match "location /api/"

如果匹配了 ^~ /static/ disable regex prefix 规则,则不再去搜索之后的 regex 规则。

$ curl http://localhost:8080/static/thinkpad.png
uri "/static/thinkpad.png": disable regex prefix match "location ^~ /static/"

在 regex 规则的匹配中,定义的先后顺序是重要的,所以 ~ \.png$ case-sensitive 规则永远不会被匹配。

$ curl http://localhost:8080/files/large.png
uri "/files/large.png": case-insesitive regex match "location ~* \.PNG(dollar)"
$ curl http://localhost:8080/files/large.PNG
uri "/files/large.PNG": case-insesitive regex match "location ~* \.PNG(dollar)"

即使先匹配了 /api/ prefix 规则作为待定,但是也匹配了 regex 规则,优先使用 regex 规则。

$ curl http://localhost:8080/api/v1/file/logo.png
uri "/api/v1/file/logo.png": case-insesitive regex match "location ~* \.PNG(dollar)"

存在 / prefix 规则是有益的,收容所有未明确定位的 uri,再做错误处理。

$ curl http://localhost:8080/no-where
uri "/no-where": prefix match "location /"

写在最后

详细解析 nginx uri 如何匹配 location 规则的更多相关文章

  1. Nginx日志参数、location匹配规则、设置密码

    1.三个参数 a)$http_referer:记录此次请求是从哪个链接访问过来的: 是直接访问,还是从其他网站跳转过来的. 例如:访问:http://www.etiantian.com/,其页面首页是 ...

  2. Nginx location指令匹配顺序规则

    location匹配命令 1. “= ”,字面精确匹配, 如果匹配,则跳出匹配过程.(不再进行正则匹配) 2. “^~ ”,最大前缀匹配,如果匹配,则跳出匹配过程.(不再进行正则匹配) 3. 不带任何 ...

  3. nginx教程1:location 匹配规则

    worker_process # 表示工作进程的数量,一般设置为cpu的核数 worker_connections # 表示每个工作进程的最大连接数 server{} # 块定义了虚拟主机 liste ...

  4. nginx里面的location 规则匹配

    nginx location语法 ~ # 区分大小写的正则匹配 location ~ \.(gif|jpg|png|js|css)$ { #规则D } ~* # 不区分大小写的正则匹配(和~的功能相同 ...

  5. Nginx配置请求转发location及rewrite规则

    一个示例: location = / { # 精确匹配 / ,主机名后面不能带任何字符串 [ configuration A ] } location / { # 因为所有的地址都以 / 开头,所以这 ...

  6. nginx配置文件结构及location块语法规则

    一. nginx配置文件结构介绍 二. location语法规则: 用法示例: location [=|~|~*|^~] /uri/ { … } # 讲解如下: 1.  = 开头表示精确匹配 2.  ...

  7. Nginx rewrite跳转 location匹配

    目录: 一.常用的Nginx 正则表达式 二.location 三.rewrite 一.常用的Nginx 正则表达式 1 ^ :匹配输入字符串的起始位置 2 $ :匹配输入字符串的结束位置 3 * : ...

  8. [日常] nginx与location规则

    =========================================================================2018年3月28日 记录: location = / ...

  9. Nginx Location规则

    Nginx由内核和模块组成,其中内核的设计非常微小和简洁,完成的工作也非常简单,仅仅通过查找配置文件将客户端的请求映射到一个location block,而location是Nginx配置中的一个指令 ...

随机推荐

  1. vcenter server appliance(vcsa) 配置IP的方法

    方法一: vcenter server appliance 5.1 及以后版本包括5.5,在安装完毕后,console界面是没有网络配置项的,如果需要进行IP配置,可以login后,输入命令yast( ...

  2. XtraEditors五、SpinEdit、TimeEdit

    SpinEdit控件 此按钮控件是用来增加或减少在编辑的文本编辑区显示的数值, 该编辑值可以是一个整数或浮点数. 其 Text属性 用于设置编辑区的文本: 其 Value属性 用于获取编辑区的值: 示 ...

  3. 2.js深入(以通俗易懂的语言解释JavaScript)

    1.函数返回值: 即函数的执行结果 可以没有return 经验:一个函数应该只返回一种类型的值 2.函数传参 可变参(不定参):arguments ——>(参数的个数可变,参数数组) 例子1:求 ...

  4. 深入学习css之background属性

    css中允许应用纯色作为背景,也允许使用图片作为背景. background一共有8个对应的属性: 1.background-color:颜色值 用于设定背景的颜色 有3种定义颜色的形式, 1, 颜色 ...

  5. CSS鼠标经过另类做法

    HTML <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3 ...

  6. linux 的常用命令---------第四阶段

    权限管理 “4” “r” → 读权限: 查看文件内容: 是否能够列出目录结构. “2” “w” → 写权限: 编辑文件内容: 是否能够创建.删除.复制.移动目录. “1” “x” → 执行权限: 对二 ...

  7. 利用 Settings Sync 同步vs code配置

    vs code上有各种各样不同的插件,如果要在不同的电脑上使用 vs code 配置是件比较麻烦的事情,使用 Settings Sync 将 vs code 配置备份起来,当需要在其他电脑使用  vs ...

  8. windows/Linux动态加载链接库问题

    windows: LoadLibraryA 指定的可执行模块映射到调用进程的地址空间并返回该 DLL 的句柄 HMODULE LoadLibraryA( LPCTSTR lpLibFileName// ...

  9. Docker学习3-CentOS安装Docker

    CentOS安装:Docker-ce ( Docker Community Edition ) 第一步:$ sudo yum install -y yum-utils device-mapper-pe ...

  10. Android给拼接好的Bitmap加上个性化边框

    在上一节中将到将若干张图片拼接成为一张图片.但是这种简单的操作往往不能满足实际的需求,有时我们会需要给图片添加上个性化的边框,来更好的展示图片. 下面就讲一下在图片拼接后如何给bitmap添加边框. ...