Nginx的 – 如何禁用重写error_page

我目前在Fedora 25 Server Edition x86_64上使用Nginx 1.10.2来托pipe一些小的静态网站。

我已经configurationNginx假定没有文件扩展名的请求( try_files )为.html ,并且如果.*\.html被请求,则redirect(永久rewrite )到URL的.html -less版本。

我也有自定义错误页面。 据我可以告诉到目前为止, error_page指令不配合重写,因为我被卡住redirect循环的网页,应该返回一个正常的错误信息…我相信这是所有相关的configuration:

 server { [...] try_files $uri $uri.html $uri/index.html =404; error_page 400 /errors/400.html; error_page 401 /errors/401.html; error_page 403 /errors/403.html; error_page 404 /errors/404.html; error_page 408 /errors/408.html; error_page 500 /errors/500.html; error_page 503 /errors/503.html; # Remove "index" from URL if requesting the front page. rewrite "^/index(\.html)?$" "/" permanent; # Strip .html file extension, trailing slash, or "index.html". rewrite "/(.+)(\.html|/|/index.html)$" "/$1" permanent; [...] } 

下面是我认为 Nginx正在做的事情:

  1. 客户端请求/fake-page
  2. 查找/fake-page/fake-page /fake-page.html/fake-page/index.html
  3. 当没有匹配时,内部redirect显示错误404页面。
  4. 但是随后/errors/404.htmlpermanent标志剥离.html,导致301用户redirect。

我已经尝试了最后一个rewrite行的几个变体,甚至把它放在一个location ^~ /errors/ {}块(我认为这应该意味着重写只适用于不在 / errors /目录下的URL)。 但是,我所做的一切都导致了一个错误404永久redirect到404 页面 ,然后不会返回实际的404状态 – 或者它最终停留在redirect循环。

我build议你在location块内包装rewrites否则很难控制其全局范围。

这个例子似乎适用于您在问题中发布的代码段:

 server { root /path/to/root; location / { # Remove "index" from URL if requesting the front page. rewrite "^/index(\.html)?$" "/" permanent; # Strip .html file extension, trailing slash, or "index.html". rewrite "/(.+)(\.html|/|/index.html)$" "/$1" permanent; try_files $uri $uri.html $uri/index.html =404; } error_page 400 /errors/400.html; error_page 401 /errors/401.html; error_page 403 /errors/403.html; error_page 404 /errors/404.html; error_page 408 /errors/408.html; error_page 500 /errors/500.html; error_page 503 /errors/503.html; location /errors/ { } } 

这是一个艰难的坚果,但最后这是按要求运作:

 server { [...] root /path/to/root; set $docroot "/path/to/root"; error_page 400 /errors/400.html; error_page 401 /errors/401.html; error_page 403 /errors/403.html; error_page 404 /errors/404.html; error_page 408 /errors/408.html; error_page 500 /errors/500.html; error_page 503 /errors/503.html; location = /errors/404.html { root $docroot; internal; } location ~ ^/index(\.html)?$ { return 301 "/"; break; } location ~ ^/$ { try_files $uri $uri.html $uri/index.html =404; break; } location ~ ^/(.+)(\.html|/|/index.html)$ { if (-f $docroot/$1) { return 301 "/$1"; break; } if (-f $docroot/$1.html) { return 301 "/$1"; break; } if (-f $docroot/$1/index.html) { return 301 "/$1"; break; } try_files missing_file =404; } location ~ ^/(.+)(?!(\.html|/|/index.html))$ { try_files $uri $uri.html $uri/index.html =404; } [...] } 

我会尽量在稍后的评论中加以扩充;)

我发现了一个更简单的解决scheme,灵感来自@ Anubioz的回答。

 server { [...] # This part's pretty common. # Assume ".html" or ".../index.html" if the original request doesn't # match any real files. Return error 404 if still can't find any # matching files. try_files $uri $uri.html $uri/index.html =404; # Match any resulting HTTP status codes with the custom error pages # that I designed. error_page 400 /errors/400.html; error_page 401 /errors/401.html; error_page 403 /errors/403.html; error_page 404 /errors/404.html; error_page 408 /errors/408.html; error_page 500 /errors/500.html; error_page 503 /errors/503.html; # Make sure the paths to the custom error pages are not transformed # before sending the actual status codes to a request. # These error pages are for *internal* use only. location = "/errors/400.html" { internal; } location = "/errors/401.html" { internal; } location = "/errors/403.html" { internal; } location = "/errors/404.html" { internal; } location = "/errors/408.html" { internal; } location = "/errors/500.html" { internal; } location = "/errors/503.html" { internal; } # Remove "index" from URL if requesting the front page. location ~ "^/index(\.html)?$" { return 301 "/"; } # Strip .html file extension, trailing slash, or index, # forcing the "pretty" URL, if user requests a ".html" URL. location ~ "^/(.+)(\.html|/|/index|/index.html)$" { return 301 "/$1"; } [...] } 

包含internal指令的location块使得通常的URL处理不会触及错误页面。 我没有尝试匹配/errors/目录,所以我不需要一遍又一遍地重复internal指令,但Nginx匹配传入的请求重写规则,基本上按规则select器的特殊性进行sorting:只与每个自定义错误页面精确匹配在Nginx可以启动URL重写过程之前,有足够的特殊性来抓取错误页面。

(我使用Nginx的术语可能会有些偏差,但是这似乎是我正在发生的事情,而这个configuration正是代码注释所说的,这是我从一开始就想要的。