try_files 指令中的 $uri 和 $uri/ 有什么区别?

flo*_*aun 2 nginx

这是配置:

\n
index index.html;\nlocation / {\n    try_files $uri $uri/ = 404;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

我在 http://localhost/path/a/ 发出请求。我假设这是 URI,因此在 $uri 阶段,try_files 将查看 /path/a/ 并提供 index.html(如果有)。

\n

我从文档中读到It is possible to check directory\xe2\x80\x99s existence by specifying a slash at the end of a name, e.g. \xe2\x80\x9c$uri/\xe2\x80\x9d.但这对我来说没有任何意义。

\n

Iva*_*sky 5

它正是$uri/使 nginx 假设 URI 可以是目录名称并在其中查找索引文件的部分。

\n

假设以下目录结构:

\n
/var/www/html\n         \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 a\n         \xe2\x94\x82   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 index.html\n         \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 b\n         \xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 index.html\n         \xe2\x94\x82   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 index.htm\n         \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 c\n         \xe2\x94\x82   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 test.html\n         ...\n
Run Code Online (Sandbox Code Playgroud)\n

以及以下 nginx 配置:

\n
server {\n    root /var/www/html;\n    index index.htm index.html;\n    location / {\n        try_files $uri $uri/ =404;\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

以下是发生的情况curl请求所发生的情况:

\n\n

如果你的 nginx 配置看起来像

\n
curl http://localhost/a\n
Run Code Online (Sandbox Code Playgroud)\n

现在,上述每个请求都会返回HTTP 404 Not Found错误。autoindex如果存在指令,则不会产生任何效果。获取index.html内容的唯一方法是明确指定它,例如http://localhost/a/index.htmlhttp://localhost/b/index.htm等等。

\n

非常重要但绝对不明显的事情是,index使用的指令try_files $uri $uri/ =404可能会导致内部重定向。例如,如果您有以下配置:

\n
HTTP/1.1 301 Moved Permanently\nLocation: http://localhost/a/\n
Run Code Online (Sandbox Code Playgroud)\n

请求将导致从tohttp://localhost/a/进行内部重定向,并返回文件内容,并将自定义标头设置为,而不是 to !/a//a/index.html/var/www/html/a/index.htmlX-Testtest2test1

\n

最后值得一提的是,这try_files $uri $uri/ =404;是默认的 nginx 行为,所以

\n
curl http://localhost/a/\n
Run Code Online (Sandbox Code Playgroud)\n

\n
curl http://localhost/b\n
Run Code Online (Sandbox Code Playgroud)\n

位置完全相等。

\n

更新

\n

OP的另一个问题:

\n
\n

我的想法是:$uri按原样检查 URI,并将$uri/URI 作为查找索引文件的目录进行检查。因为我得到http://localhost/a了。目前还好!因为我也得到了。为什么?我正期待着。此外,还会给我带来.try_files $uri /file.html =404;file.htmlhttp://localhost/atry_files $uri/ /file.html =404;file.htmlindex.htmltry_files $uri $uri/ /file.html =404;index.html

\n
\n

真是个好问题!如果不回答这个问题,整个答案就会显得不完整。让我们看看这里发生了什么。

\n

将请求http://localhost/a/try_files $uri/ /file.html =404;指令放入 nginx 配置中后,第一步 nginx 检查该/var/www/html/a/目录是否为目录,接下来检查其是否存在索引文件,index.html在其中找到一个文件并进行从/a/到 的内部重定向/a/index.html。第二步,在同一个位置块内,nginx 检查是否/var/www/html/a/index.html是一个目录,但它不是!由于您没有$uri组件作为try_files指令参数,因此它会进行下一次文件检查/var/www/html/file.html,找到它并返回其内容。

\n

因此,您可能认为使用try_files不带参数的指令是完全没有用的。$uri通常是这样,但也可以作为这样做的用例,例如当您想要隐藏内部站点结构时。这是一个例子:

\n
HTTP/1.1 301 Moved Permanently\nLocation: http://localhost/b/\n
Run Code Online (Sandbox Code Playgroud)\n

使其成为内部的,您可以防止通过诸如(将返回)之类的请求location ~ /index\\.html$ { ... }直接访问您的文件。然而,由于内部 URI 被指令和 1 一起重写,类似的请求仍然可行。index.htmlhttp://localhost/a/index.htmlHTTP 404 Not Foundhttp://localhost/a/indextry_files $uri/ =404

\n