如何控制 NGINX 'Location' 指令匹配顺序?

Posted

技术标签:

【中文标题】如何控制 NGINX \'Location\' 指令匹配顺序?【英文标题】:How to control NGINX 'Location' directive matching order?如何控制 NGINX 'Location' 指令匹配顺序? 【发布时间】:2012-01-16 06:43:54 【问题描述】:

我正在尝试优化我的“位置”指令,但找不到确定是否尝试特定位置匹配的好方法。在 location 块中使用 echo 在这里没有帮助。

The nginx ngx_http_core_module documentation 有点混乱。

要使用正则表达式,必须使用前缀:

    ~ 用于区分大小写的匹配

    ~* 用于不区分大小写的匹配

比赛是如何进行的:

    带有 = 前缀的指令与查询完全匹配。如果找到,则停止搜索。

    所有剩余的指令都带有常规字符串。如果此匹配使用了^~ 前缀,则停止搜索。

    正则表达式,按照它们在配置文件中定义的顺序。

    如果 #3 产生匹配,则使用该结果。否则,使用 #2 中的匹配项。

这里的数字 2 表示“常规字符串”,但随后表示它可以与 ^~ 前缀一起使用。 ~ 不是暗示正则表达式吗?如果不是,它如何确定什么是非正则表达式?

具体来说,我想要以下内容:

    直接提供文字 /assets 之外的任何内容。停止搜索。

    通过快速 CGI STOP SEARCH 提供与 RegExp \.php$|/$ 匹配的任何内容。

    直接通过文字/提供其他所有内容

这样,只有/ 匹配从资产外部提供的非动态文件的尝试。

我有:

location ^~ /assets       # search-terminating literal? or regex?
location ~ \.php$|/$ 
location /                # is this match always attempted?

从文档看来,实际顺序似乎是 1-3-2,始终运行文字 / 匹配。是的,这种优化不会对实际性能产生任何影响,但我只是想澄清一些歧义。

【问题讨论】:

【参考方案1】:

来自维基:

location  = / 
  # matches the query / only.
  [ configuration A ] 

location  / 
  # matches any query, since all queries begin with /, but regular
  # expressions and any longer conventional blocks will be
  # matched first.
  [ configuration B ] 

所以,这将首先匹配: location ~ \.php$

即使资产是由location / 提供的

在 php 块中,您还希望在传递给 fastcgi 之前防止恶意上传:

if ($uri ~* "^/uploads/") 
  return 404;

如您所见,nginx 的工作方式与您预期的略有不同。

【讨论】:

我仍然不清楚为什么首先匹配正则表达式。授予没有“=”指令。接下来是“所有剩余的带有常规字符串的指令”。 '/' 是一个常规字符串,应该在任何正则表达式之前匹配。整个 strings-then-regex 是 nginx 似乎在这里做的一个手持隐式优化,这使得很难确定评估的真实顺序。我认为 apache/iptables 等可以通过以定义为 if/else-if/else 块的相同顺序进行可预测的处理来正确处理。没有任何隐含的“更多/更少”特定规则。 对,这对 nginx 肯定有点混乱,尤其是 nginx 的 if 应该只用于 rewrite/return。我认为他们正在努力简化这一点。对于您的情况,它将像这样工作: 1. php regex 检查是否匹配 2. / 任何静态内容。 您的订单有误。首先将 /assets 规则作为字符串的全部意义在于避免在每个请求上运行 php 正则表达式的开销。事实上,我想在不通过 FCGI 的情况下提供像 assets/docs/example.php 这样的东西。我目前正在运行此设置,并且正则表达式不会捕获 example.php。它的顺序为 ^~ /assets, /, ~ \.php$|/$ 您可以在 nginx 上的某个地方询问是否可以完全这样做。另请查看try_files。不过,在 Apache 上使用 nginx 可以提高性能 :) 是的,我知道,正如我在 OP 中指出的那样,这实际上与性能无关,而是与理解匹配规则的清晰度有关。它们的隐含性/复杂性使它们更难维护、容易出错,因此安全性较低

以上是关于如何控制 NGINX 'Location' 指令匹配顺序?的主要内容,如果未能解决你的问题,请参考以下文章

Nginx的Location正则表达式

nginx rewrite

一文彻底读懂nginx中的location指令

如何正确配置Nginx + PHP

Nginx正则配置

Nginx 指令之location