迹忆客 专注技术分享

当前位置:主页 > 学无止境 > 网络 >

深入理解 Nginx Location 块匹配算法

作者:迹忆客 最近更新:2023/01/08 浏览次数:

Nginx 用于选择将处理请求的 Server 块 的过程类似,Nginx 也有一个既定的算法来决定 Server 块中的哪个 Location 块用于处理请求。

location 块语法

在我们讨论 Nginx 如何决定使用哪个 location 块来处理请求之前,让我们回顾一下可能在 location 块定义中看到的一些语法。 location 块位于 server 块(或其他 location 块)中,用于决定如何处理请求 URI(请求中位于域名或 IP 地址/端口之后的部分)。

location 块通常采用以下形式:

location optional_modifier location_match {

    . . .

}

上面的 location_match 定义了 Nginx 应该检查请求 URI 的对象。 上例中修饰符的存在与否会影响 Nginx 尝试匹配位置块的方式。

  • (none) :如果不存在修饰符,则该 location 被解释为前缀匹配。 这意味着给定的location 将与请求 URI 的开头进行匹配以确定匹配。
  • = :使用等号,如果请求 URI 与给定location 完全匹配,则此块将被视为匹配。
  • ~ :如果存在波浪号修饰符,则此 location 将被解释为区分大小写的正则表达式匹配。
  • ~* :如果使用波浪号和星号修饰符,则 location 块将被解释为不区分大小写的正则表达式匹配。
  • ^~ :如果存在 ^ 和波浪号(~)修饰符,并且如果该块被选为最佳非正则表达式匹配,则不会进行正则表达式匹配。

Location 块语法示例

作为前缀匹配的示例,可以选择以下 location 块来响应类似于 /site、/site/page1/index.html 或 /site/index.html 的请求 URI:

location /site {

    . . .

}

为了演示精确的请求 URI 匹配,此块将始终用于响应看起来像 /page1 的请求 URI。 它不会用于响应 /page1/index.html 请求 URI。 请记住,如果选择此块并且使用索引页面完成请求,则内部重定向将跳转到另一个 location,该块将是请求的实际处理程序:

location = /page1 {

    . . .

}

作为应解释为区分大小写的正则表达式的位置示例,此块可用于处理对 /tortoise.jpg 的请求,但不适用于 /FLOWER.PNG:

location ~ \.(jpe?g|png|gif|ico)$ {

    . . .

}

下面显示了一个允许与上面类似的不区分大小写匹配的块。 在这里,/tortoise.jpg 和 /FLOWER.PNG 都可以由这个块处理:

location ~* \.(jpe?g|png|gif|ico)$ {

    . . .

}

最后,如果确定为最佳非正则表达式匹配,此块将不进行正则表达式匹配。 它可以处理 /costumes/ninja.html 的请求:

location ^~ /costumes {

    . . .

}

如您所见,修饰符表示应如何解析 location 块。 但是,这并没有告诉我们 Nginx 用来决定将请求发送到哪个 location 块的算法。 接下来我们将讨论这个问题。

Nginx 如何选择使用哪个 location 来处理请求

Nginx 以与选择 Server 块类似的方式选择将用于服务请求的 location 块。 它有一个为任何给定请求确定最佳 location 块的过程。 了解这个过程是能够可靠、准确地配置 Nginx 的关键要求。

记住我们上面描述的 location 声明的类型,Nginx 通过将请求 URI 与每个 location 块进行比较来评估可能的上下文。 它使用以下算法执行此操作:

  • Nginx 首先检查所有基于前缀的 location 匹配(所有不涉及正则表达式的位置类型)。它根据完整的请求 URI 检查每个位置。
  • 首先,Nginx 寻找完全匹配。如果发现使用 = 修饰符的 location 块与请求 URI 完全匹配,则立即选择此块来为请求提供服务。
  • 如果没有找到精确的(使用 = 修饰符)location 块匹配,Nginx 然后继续评估非精确前缀。它发现给定请求 URI 的最长匹配前缀块,然后检查如下:
  • 如果最长匹配的前缀位置有 ^~ 修饰符,那么 Nginx 将立即结束搜索并选择该 location 块来服务请求。
  • 如果最长匹配前缀位置不使用 ^~ 修饰符,则匹配由 Nginx 暂时存储,以便可以转移搜索的焦点。
  • 在确定并存储最长匹配前缀位置后,Nginx 继续检查正则表达式location (区分大小写和不区分大小写)。如果最长匹配前缀块中有任何正则表达式的location,Nginx 会将这些移动到其正则表达式 location 列表的顶部来进行检查。 Nginx 然后尝试按顺序匹配正则表达式 location。与请求 URI 匹配的第一个正则表达式 location 会立即被选择来为请求提供服务。
  • 如果没有找到与请求 URI 匹配的正则表达式 location,则选择先前存储的前缀 location 来为请求提供服务。

重要的是要理解,默认情况下,Nginx 将优先提供正则表达式匹配而不是前缀匹配。 但是,它首先评估前缀 location ,允许管理员通过使用 =^~ 修饰符指定 location 来覆盖这种趋势。

还需要注意的是,虽然前缀 location 通常根据最长、最具体的匹配进行选择,但在找到第一个匹配项时会停止正则表达式匹配。 这意味着配置中的定位对正则表达式location有很大的影响。

最后,重要的是要了解,当 Nginx 评估正则表达式时,最长前缀匹配中的正则表达式匹配将“跳线”。 在考虑任何其他正则表达式匹配之前,将按顺序评估这些。

评估 location 块何时跳转到其他 location?

只有选定的 location 和继承的指令确定如何处理请求,而不受兄弟 location 块的干扰。

尽管这是一条允许我们以可预测的方式设计location块的一般规则,但重要的是要意识到有时新的 location 搜索会由所选块内的某些指令触发。 “只有一个location块”规则的例外情况可能会影响请求的实际服务方式,并且可能与我们在设计location块时的期望不一致。

一些可能导致这种类型的内部重定向的指令是:

  • index
  • try_files
  • rewrite
  • error_page

如果 index 指令用于处理请求,它总是会导致内部重定向。 精确匹配通常用于通过立即结束算法的执行来加速选择过程。 但是,如果进行目录的精确匹配,则请求很有可能被重定向到不同的块来实际进行处理。

在这个例子中,第一个location由 /exact 的请求 URI 匹配,但为了处理请求,块继承的 index 指令会启动到第二个块的内部重定向:

index index.html;

location = /exact {

    . . .

}

location / {

    . . .

}

在上述情况下,如果确实需要执行停留在第一个块中,我们将不得不想出一种不同的方法来满足对目录的请求。 例如,可以为该块设置无效 index 并打开autoindex

location = /exact {
    index nothing_will_match;
    autoindex on;
}

location  / {

    . . .

}

这是防止索引切换上下文的一种方法,但它可能对大多数配置没有用。 大多数情况下,目录上的完全匹配可能有助于重写请求(这也会导致新的位置搜索)。

可以重新评估处理location的另一个实例是使用 try_files 指令。 该指令告诉 Nginx 检查是否存在命名的文件或目录集。 最后一个参数可以是 Nginx 将进行内部重定向的 URI。

看下面的配置

root /var/www/main;
location / {
    try_files $uri $uri.html $uri/ /fallback/index.html;
}

location /fallback {
    root /var/www/another;
}

在上面的示例中,如果对 /blahblah 发出请求,则第一个location最初会收到请求。 它将尝试在 /var/www/main 目录中找到一个名为 blahblah 的文件。 如果找不到,它将通过搜索名为 blahblah.html 的文件来跟进。 然后它将尝试查看 /var/www/main 目录中是否有一个名为 blahblah/ 的目录。 如果所有这些尝试都失败,它将重定向到 /fallback/index.html。 这将触发另一个location搜索,该搜索将被第二个块捕获。 这将提供文件 /var/www/another/fallback/index.html

另一个可能导致 location 块传递的指令是 rewrite 指令。 当使用 rewrite 指令的最后一个参数时,或者根本不使用参数时,Nginx 将根据 rewrite 的结果搜索新的匹配块。

例如,如果我们修改最后一个示例使其包含 rewrite,我们可以看到请求有时会直接传递到第二个location块,而不依赖于 try_files 指令:

root /var/www/main;
location / {
    rewrite ^/rewriteme/(.*)$ /$1 last;
    try_files $uri $uri.html $uri/ /fallback/index.html;
}

location /fallback {
    root /var/www/another;
}

在上面的示例中,对 /rewriteme/hello 的请求最初将由第一个 location 块处理。它将被重写为 /hello 并搜索一个块。在这种情况下,它将再次匹配第一个 location 并像往常一样由 try_files 处理,如果没有找到可能会返回到 /fallback/index.html(使用我们上面讨论的 try_files 内部重定向)。

但是,如果对 /rewriteme/fallback/hello 发出请求,第一个块将再次匹配。再次应用重写,这一次导致 /fallback/hello。然后将在第二个location块之外提供请求。

发送 301 或 302 状态代码时,return 指令会发生相关情况。这种情况下的不同之处在于,它会以外部可见重定向的形式产生一个全新的请求。在使用 redirectpermanent 标志时,rewrite 指令可能会发生同样的情况。然而,这些location 搜索不应该是意料之外的,因为外部可见的重定向总是会产生一个新的请求。

error_page 指令可以导致类似于 try_files 创建的内部重定向。该指令用于定义遇到某些状态代码时应该发生的情况。如果设置了 try_files,这可能永远不会执行,因为该指令处理请求的整个生命周期。

我们看下面的例子

root /var/www/main;

location / {
    error_page 404 /another/whoops.html;
}

location /another {
    root /var/www;
}

每个请求(除了那些以 /another 开头的请求)都将由第一个块处理,该块将提供来自 /var/www/main 的文件。 但是,如果未找到文件(404 状态),则会发生内部重定向到 /another/whoops.html,从而导致新的location搜索并最终会落在第二个块上。 该文件将从 /var/www/another/whoops.html 提供。

如我们所见,了解 Nginx 触发新location搜索的情况有助于预测在发出请求时会看到的行为。

总结

了解 Nginx 处理客户端请求的方式可以使我们作为管理员的工作更加轻松。 能够知道 Nginx 将根据每个客户端请求选择哪个Server 块。 还可以根据请求 URI 判断如何选择 location 块。 总体而言,了解 Nginx 选择不同块的方式将使我们能够跟踪 Nginx 上下文,应用这些更好的为每个请求提供服务。

转载请发邮件至 1244347461@qq.com 进行申请,经作者同意之后,转载请以链接形式注明出处

本文地址:

相关文章

Nginx 和 uWISG 服务器之间如何配合工作的

发布时间:2023/03/29 浏览次数:158 分类:网络

Nginx和uWISG是两个常用的服务器软件,它们可以协同工作以提供更加稳定和高效的网络服务。本文将详细介绍Nginx和uWISG之间的配合工作原理,以及如何配置它们以实现最佳性能。 一、

设置 PHP-FPM 和 Nginx Docker 容器

发布时间:2023/03/29 浏览次数:147 分类:PHP

在本篇文章中,我们将讨论在 Docker 上进行本地开发时如何设置 PHP、PHP-FPM 和 NGINX 容器。

在 Ubuntu 18.04 上使用 Nginx 安装 WordPress

发布时间:2022/10/15 浏览次数:223 分类:操作系统

WordPress 是最受欢迎的开源内容管理系统 (CMS) 之一,与 Drupal 或 Joomla 等其他 CMS 相比,其市场份额高达 60%。 WordPress 可用于开发任何类型的网站,无论是博客、小型企业还是大型企业。

Nginx 运行但是不提供站点服务

发布时间:2022/05/15 浏览次数:186 分类:网络

我们最近在一台新机器上安装了 nginx 版本 1.17。 在 sites-available`中创建的配置被符号链接到 `sites-enabled` ,但 nginx 没有为任何域名提供服务。

Nginx 如何修复 Unknown "connection_upgrade" Variable 错误

发布时间:2022/03/28 浏览次数:4924 分类:网络

在使用 Websockets 或使用 nginx 配置服务器时,我们可能会在 nginx 配置中遇到 `$connection_upgrade` 变量。 $connection_upgrade 变量默认不可用。 但是,建议在反向代理设置中定义和使用它。

深入理解 Nginx 的 Server 块选择算法

发布时间:2022/01/13 浏览次数:91 分类:网络

在本篇文章中,我们将讨论一些决定 Nginx 处理客户端请求的细节。 了解这些可以帮助我们在设计 Server 和 Location 时更加得心应手,对于一些请求的现象不至于迷惑。

扫一扫阅读全部技术教程

社交账号
  • https://www.github.com/onmpw
  • qq:1244347461

最新推荐

教程更新

热门标签

扫码一下
查看教程更方便