如何在 nginx 中设置后备错误页面?

如何在 nginx 中设置后备错误页面?

我目前正在配置 nginx 对某些错误页面和其他“默认”媒体文件(例如 favicon.ico 和 robots.txt)的处理,并且在使某些错误页面按照我想要的方式工作时遇到了一个小问题。

基本上,我想做的是为该服务器的根目录下的服务器提供某些文件,例如 /var/www/someserver.com/robots.txt。如果该文件不存在,我希望 nginx 转到“默认”,即 /var/www/default/robots.txt。这是我(成功)配置的基本要点:

server {
    ...
    root /var/www/someserver.com;

    location ~* ^/(robots\.txt)$ {
        error_page 404 = @default;
    }

    location @default {
        root /var/www/default;
    }
}

效果很好。

我正在尝试对错误页面执行相同的操作,但是却无法实现:

server {
    ...
    root /var/www/someserver.com;

    error_page 404   /404.html;

    location ~* ^/(404\.html)$ {
        error_page 404 = @default;
    }

    location @default {
        root /var/www/default;
    }
}

请注意,此方法“有效”的意思是,如果您访问 someserver.com/404.html,它将首先尝试加载 /var/www/someserver.com/404.html,如果未找到,则返回到 /var/www/default/404.html。但是,如果您访问 someserver.com/blahblah,则仅当在 /var/www/someserver.com/ 中设置了 404 页面时,它才会显示该页面。如果该文件不存在,则它不会返回到默认目录。

无论如何,您可能已经了解我想要完成的事情(这就是我包含第一个工作示例的原因)。

有任何想法吗?

编辑:

根据 Martin F 的回答,我最终得出了以下结论:

# Doesn't work when error page is returned on a POST request
server {
    ...
    root /var/www/someserver.com;

    error_page  404         = @notfound;
    error_page  500 502 504 = @server_error;
    error_page  503         = @maintenance;

    location @notfound {
        try_files /404.html /../default/404.html =404;
    }

    location @server_error {
        try_files /500.html /../default/500.html =500;
    }

    location @maintenance {
        try_files /503.html /../default/503.html =503;
    }
}

这真是太棒了。上面的 error_pages 和 locations 的实际块位于 server_defaults.conf 文件中,该文件包含在每个虚拟主机中,这就是为什么我没有将路径硬编码到每个位置,而是对默认值使用相对路径。

编辑2:

这种方法存在一个问题。如果您向返回错误的 URL 发送 POST 请求,则 POST 请求方法将与 try_files 尝试一起发送。这(对我来说)会导致 405 Not Allowed 错误,因为 nginx 本质上是尝试向 /default/500.html 发送 POST 请求,而不是仅获取该页面。

编辑3:

我发布了一个可行的解决方案,它与我最初的想法更加接近。

答案1

我最终选择了更接近我最初想法的东西。我所缺少的关键原来是指令recursive_error_pages。我真正需要做的就是将其“打开”,这样我最初的想法就奏效了。下面是我的 conf 的相关部分现在的样子:

server {
    ...

    root /var/www/someserver.com/;

    error_page 400 404      /404.html;
    error_page 500 502 504  /500.html;
    error_page 503          /503.html;

    recursive_error_pages   on;

    location ~* ^/(404\.html|500\.html|503\.html)$ {
        log_not_found off;
        error_page 404 = @default;
    }

    location @default {
        log_not_found on;
        root /var/www/default;
    }
}

我在这里添加了其他错误类型,这些错误类型不是我原始问题的一部分,因为这就是 Martin F 的方法给我带来的麻烦,而 Martin F 的方法在其他方面都很棒。该log_not_found指令只是确保当在原始根目录中找不到错误页面时,我的日志中不会出现 404 错误。

答案2

try_files是此处要采用的方法。以下配置应该可以工作,但我尚未测试其语法错误。

server {
    ...
    root /var/www;

    location / {
        try_files /someserver.com$uri /default$uri /someserver.com$uri/ /default$uri/ @notfound;
    }

    location @notfound {
       try_files /someserver/404.html /default/404.html =404; # =404 should make it use the nginx-default 404 page.
    }
}

答案3

不幸的是,我的答案晚了几年,但我认为它可能对未来的搜索者有所帮助。我安装的 Nginx 版本是 1.2.4,我创建了以下配置片段,

server {

server_name www.example.com
root /var/www/example


## Errors -> Locations
error_page   400 /400.html;
error_page   403 /403.html;
error_page   404 /404.html;
error_page   500 502 503 504 /50x.html;

## Locations -> Fallback
location = /400.html {
    try_files /400.html @error;
    internal;
}
location = /403.html {
    try_files /403.html @error;
    internal;
}
location = /404.html {
    try_files /404.html @error;
    internal;
}
location = /50x.html {
    try_files /50x.html @error;
    internal;
}

## Fallback Directory
location @error {
    root /var/www/error;
}

}

答案4

我发现在任何包含 error_page 的位置块中包含“proxy_intercept_errors on;”至关重要。

如果没有此设置,则位置块将拦截从上游返回的错误代码。

http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_intercept_errors

相关内容