NGINX 到底是怎么处理 try_files 和 index 指令的

NGINX 到底是怎么处理 try_files 和 index 指令的

Chris Yue No Comment
Posts

try_files 和 index 两个指令,有一个相似之处,即都是用于处理访问路径与实际物理文件不匹配的情况下,如何返回内容的问题,并且都涉及到内部跳转的问题。这两个指令看似都很简单,但如果不清楚这两个指令的执行效果,可能会出现意想不到的输出结果。为了能将这个问题说清楚,我做了一些实验,本文就是对这些实验的一个总结。

需要注意的是,本文所有实验结果基于 NGINX 版本 1.17.0。结果可能会因为版本的不同而有所变化。

TL;DR

先说结论:

  • index 指令会导致内部跳转,try_files 除了最后一个参数,不会导致内部跳转
  • 内部跳转将会让 NGINX 重新尝试匹配 location 并运行其设置

为了将问题分得更细,我先单独说 index 指令

index 指令

大家都知道 index 指令,只用于访问路径为目录形式的时候才有用,但大家是否能立马回答这个问题:假如配置了 index index.html,请问在访问 example.com/a/ 这个路径的时候,如果服务器不存在 a/index.html 这个文件,但有配置关于 location = /a/index.html 的返回,请问访问的结果是什么?

我这里访问的结果为:访问 /a/index.html 返回 hello;访问 /a/ 返回 404。看起来 index 指令并不是直接在访问路径上尝试追加指定的文件名,而是在被访问的物理目录上追加文件名。

不过,假如 a/index.html 文件是存在的,NGINX 应该会有内部跳转的处理,导致 $uri 变成了 /a/index.html,即匹配了 location 那一行的配置,那么新的问题又来了:当 a/index.html 物理文件存在的情况下,上面的配置是返回物理文件的内容?还是返回 location 配置里的内容?

尝试写一个内容为 byeindex.html 放在 a 目录下,访问的结果为 hello,即新增的物理文件让 NGINX 觉得 /a/ 路径存在,但实际的输出还是按 location 指令执行的。

这个结果并不意外,毕竟官方文档里对此已有单独的说明。

try_files 指令

因为 NGINX 的配置脱离不了 index 指令,所以本节要将 try_files 和 index 的相互影响一起说。

try_files 指令大家也应该比较熟悉,即当访问的物理路径不存在时,尝试按照 try_files 指定的路径的顺序查找,并返回最先匹配到的路径结果。不过仔细推敲,跟 index 指令类似,当我们说匹配路径时,又有匹配『访问路径』和『物理文件路径』两种解释,那到底是按哪一种呢?我们也可以通过做实验来观察。

假如 a/index.html 物理文件依然不存在的情况,下面的配置访问 /a/ 将如何返回

假设根目录下 foo.html 物理文件存在,内容为 foo

我这里的测试结果:

  • 当 a 目录不存在时,返回 foo
  • 当 a 目录存在时,返回 403

第一种情况应该好理解,try_files 指令的典型用法;第二种情况,可能可以这么理解:当 NGINX 发现的确存在 a 这个物理目录,结合 index 指令,尝试访问 a/index.html,然而此文件却因不存在无法读取,只能返回 403。如果此理解是对的,当我们将 a/index.html 恢复后,应该就可以访问了,但又有新的问题出现:访问的结果是 a/index.html 物理文件的内容?还是 location = /a/index.html 那一段配置的内容?

我的试验结果为:hello,即 location 的配置返回的结果。这个结果看起来还是合理的,跟 index 那次的结果一致。

按理来说,如果设置 index index.html,则在配置 try_files 的时候, $uri/ 跟写成 $uri/index.html 应该是一样的意思,实际是否如此,我们依然可以通过实验得出。首先修改配置如下

测试结果为:bye,即 a/index.html 文件的内容。似乎又可以得出一个结论:try_files 不同于 index 指令,是不会出现内部跳转的……吗?

这个问题实际上官网文档也有详细的解释,try_files 最后一个参数并不同于前面几个参数,它不是指物理路径,而是访问路径,按文档的说法,最后一个参数是会出现内部跳转的(也就是说非最后一个参数都不会)。不妨再次修改一下上面的配置,做个测试:

以上配置,直接访问非 /a/ 或者 /a/index.html 的任何路径,都应该被 try_files 内部跳转到 /foo.html 路径,虽然 /foo.html 物理文件本身存在,但因为 /foo.html 路径有自己单独的 location 配置,按猜想应该是按配置返回 bar 而不是文件本身的内容 foo,实际测试的结果的确为 bar

NGINX 到底是怎么处理 try_files 和 index 指令的 by Chris Yue is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.

微信赞赏码

文章不错,我要帮站长分担建站费!
天使投赏人

发表评论

+ 21 = 23