如果文件夹不存在,Nginx 显示自定义错误页面

问题描述 投票:0回答:1

如果缺少文件夹,我想显示自定义错误页面。

我的目录结构如下:

data
   defaults
      error.html
      nothosted.html
   example.com
      misc
         error.html
   example.net
   ...

因此,当有人访问 example.de 且其文件夹不存在时,将显示 defaults/nothosted.html。但如果该文件夹存在,则应使用我的@error 位置。

目前这是我的配置,不起作用。

    server_name ~^(\*\.)?(?<subdomain>[a-z\d][a-z\d-]*[a-z\d]\.)(?<domain>.+)+$;

    location / {
        root /data/$subdomain$domain;
        try_files $uri $uri/ @nothosted;
        index index.html index.htm index.php;
    }

    location @nothosted {
        root      /data;

        set $link /$subdomain$domain;

        if (!-d $link) {
           set $link /defaults/nothosted.html;
        }

        try_files  $link @error;
    }

    error_page 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 421 422 423 424 425 426 428 429 431 451 500 501 502 503 504 505 506 507 508 510 511 @error;
    location @error {
        internal;
        ssi         on;
        auth_basic  off;
        root        /data;
        try_files   /$subdomain$domain/misc/error.html /$domain/misc/error.html /defaults/error.html =404;
    }

我在 nginx 日志中收到的错误如下:

*1 directory index of "/data/" is forbidden

我尝试连接到文件夹不存在的域时遇到的错误是来自 @error 位置的“403 禁止”。

权限应该正确(整个 /data/ 文件夹归 nginx 用户所有)

编辑: 使用以下非托管位置时,访问后网页上会显示正确的链接。所以问题一定出在 try_files 函数上。

    location @nothosted {
        root      /data;

        set $link /$subdomain$domain;

        if (!-d $document_root/$subdomain$domain) {
           set $link /defaults/nothosted.html;
        }

        return 200 $link;
        add_header Content-Type text/plain;
    }
nginx custom-error-pages
1个回答
1
投票

这个问题无法按照您尝试解决的方式解决。原因是,当在

if
上下文中使用时,location
 是邪恶的
。我早就知道这一点,但我不知道有时它会如此邪恶。

通常 nginx 配置指令是声明性的(例如,将像

proxy_pass
这样的指令放置在哪里没有区别,它可以放置在任何地方的确切位置内)。虽然来自重写模块的常见 nginx 指令是唯一可以被视为命令式的指令(请参阅模块文档中的内部实现章节),但
if
指令是一种非常特殊的情况。在阅读了上述实现描述后,很长一段时间我认为仅使用
if
块内的重写模块中的指令将使这样的块完全安全。不幸的是,这不是真的。关于该指令实际工作原理的最佳描述之一是由著名的 lua-nginx-moduleOpenResty 包的作者 Yichun Zhang 制作的。事实上,每个 if
 指令都隐式创建一个嵌套位置,该位置尝试从父级继承所有声明。然而,
try_files
指令不会被继承(nginx trac
ticket),并且如果选择这样的虚拟嵌套位置来处理请求并具有static内容处理程序,则将具有默认的PRECONTENT
阶段 处理程序类似于 try_files $uri $uri/ =404
。您收到的错误消息来自以下事实:隐式 
try_files
 指令尝试使用当前 URI(可能是 
/
 URI),并且隐式 
index
 指令无法在 webroot 
/data
 目录中找到索引文件。 

也就是说,选择的方法不起作用。您可以尝试以下方法:

if (!-d /data/$subdomain$domain) { rewrite ^ /defaults/nothosted.html; } location / { root /data/$subdomain$domain; try_files $uri $uri/ =404; index index.html index.htm index.php; } location = /defaults/nothosted.html { internal; root /data; } error_page 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 421 422 423 424 425 426 428 429 431 451 500 501 502 503 504 505 506 507 508 510 511 @error; location @error { internal; ssi on; auth_basic off; root /data; try_files /$subdomain$domain/misc/error.html /$domain/misc/error.html /defaults/error.html =404; }
此解决方案有一个缺点 - 

/defaults/nothosted.html

 URI 不适用于任何托管站点。如果您发现它不可接受,您可以使用某种唯一的随机字符串来代替 
nothosted
 字符串(并相应地重命名该 
nothosted.html
 文件)。

© www.soinside.com 2019 - 2024. All rights reserved.