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

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

这是配置:

index index.html;
location / {
    try_files $uri $uri/ = 404;
}

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

我从文档中读到这一点,It is possible to check directory’s existence by specifying a slash at the end of a name, e.g. “$uri/”.但这对我来说没有任何意义。

答案1

正是这个$uri/部分使得 nginx 假设 URI 可以是目录名并在其中寻找索引文件的存在。

假设目录结构如下:

/var/www/html
         ├── a
         │   └── index.html
         ├── b
         │   ├── index.html
         │   └── index.htm
         ├── c
         │   └── test.html
         ...

以及以下 nginx 配置:

server {
    root /var/www/html;
    index index.htm index.html;
    location / {
        try_files $uri $uri/ =404;
    }
}

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

  • curl http://localhost/a
    

    返回重定向:

    HTTP/1.1 301 Moved Permanently
    Location: http://localhost/a/
    
  • curl http://localhost/a/
    

    返回/var/www/html/a/index.html文件内容。

  • curl http://localhost/b
    

    返回重定向:

    HTTP/1.1 301 Moved Permanently
    Location: http://localhost/b/
    
  • curl http://localhost/b/
    

    返回/var/www/html/b/index.htm文件内容(按照使用指令指定的顺序检查索引文件的存在index)。

  • curl http://localhost/c
    

    返回重定向:

    HTTP/1.1 301 Moved Permanently
    Location: http://localhost/c/
    
  • curl http://localhost/c/
    

    由于目录中没有索引文件/var/www/html/c/,除非您的配置中有一个指令(在这种情况下 nginx 将返回目录列表),否则curl命令将返回。HTTP 403 Forbiddenautoindex on;/var/www/html/c/

如果你的 nginx 配置如下

server {
    root /var/www/html;
    index index.htm index.html;
    location / {
        try_files $uri =404;
    }
}

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

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

server {
    root /var/www/html;
    index index.htm index.html;
    location / {
        add_header X-Test test1;
        try_files $uri $uri/ =404;
    }
    location /a/index.html {
        add_header X-Test test2;
    }
}

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

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

location / {
    try_files $uri $uri/ =404;
}

location / {}

位置完全相同。

更新

OP 的另一个问题:

我的想法是:$uri检查 URI 本身,并将$uri/URI 作为查找索引文件的目录进行检查。对于http://localhost/a使用,try_files $uri /file.html =404;我得到了file.html。现在很好!对于http://localhost/a使用,try_files $uri/ /file.html =404;file.html也得到了 。为什么?我期望index.html。此外,try_files $uri $uri/ /file.html =404;将为我提供index.html

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

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

因此,您可能会认为使用try_files不带$uri参数的指令完全没用。通常情况下确实如此,但在某些情况下也可以这样做,例如当您想要隐藏内部站点结构时。以下是示例:

server {
    root /var/www/html;
    index index.html;
    location / {
        try_files $uri/ =404;
    }
    location ~ /index\.html$ {
        internal; # only accessible via internal URI rewrite
        try_files $uri =404;
    }
    location ~ \.(js|css|jpe?g|png)$ {
        # serve the assets in a usual way
        try_files $uri =404;
    }
}

使其成为内部请求后,您将无法通过类似这样的请求location ~ /index\.html$ { ... }直接访问您的文件(将返回一个)。但是,由于内部 URI 重写指令与一个指令一起使用,类似这样的请求仍然可行。index.htmlhttp://localhost/a/index.htmlHTTP 404 Not Foundhttp://localhost/a/indextry_files $uri/ =404

相关内容