Using error_page to a named location - possible?

Maxim Dounin mdounin at mdounin.ru
Tue Mar 6 23:28:55 UTC 2012


Hello!

On Tue, Mar 06, 2012 at 10:32:56PM +0000, Ed W wrote:

> On 06/03/2012 17:47, Maxim Dounin wrote:
> >>I can't see that it's possible to use something like:
> >>
> >>   location / {
> >>     proxy_pass http://127.0.0.1:3000;
> >>     error_page 502 @502;
> >>   }
> >>
> >>location @502 {
> >>   index /502.html;
> >>   root /var/www;
> >>   internal;
> >>}
> >Try something like:
> >
> >     location @502 {
> >         internal;
> >         root /var/www;
> >         rewrite ^ /502.html break;
> >     }
> >
> >This should work at least for GET requests.
> 
> Perfect - thanks!
> 
> 
> Now, I have thought about this a little while and I don't quite
> understand how it works...?
> 
> The key seems to be the rewrite clause - near as I can see, without
> this the error request gets reprocessed by the "location /" section,
> but the rewrite is causing it to terminate that?
> 
> Can you teach me to understand this please?

Under normal conditions 

    location @502 {
        root /var/www;
    }

will behave much like normal static location, as described here:

http://nginx.org/en/docs/http/request_processing.html

That is, request to a "/file", if it happens to hit his location, 
will be processed as follows:

1. It doesn't ends with '/', hence nginx will try to open a file 
   for it, <root> + <uri>.  I.e. "/var/www/file" will be opened.

2. The (1) will likely fail (as there is no such file) and will 
   generate 404.

More importantly, request to a "/" will be processed as 
follows:

1. It ends with "/", so nginx will try to use index module to 
   handle it.

2. Index module will test <root> + <uri> + <index> file, i.e. 
   "/var/www/502.html" with your config.  If it's found - nginx will 
   do internal redirect to "/502.html".

3. The internal redirect will end up in "location /".  This is 
   obviously not what you want.

With "rewrite ^ /502.html break;" the following two important 
things happen:

a. Every request will be a request to a file (i.e. no internal 
   redirects).  Note that "break" is important, without "break" nginx 
   will re-do location matching again after rewrite.

b. Every request will be a request to the "/var/www/502.html" 
   file.

That is, every GET request which hits the @502 location will 
return the /var/www/502.html.

Note well:

For POSTs things won't be that easy, as error_page set to a named 
location won't change request method to GET (in contrast to 
error_page set to a uri), and the above will generate 405 Method 
Not Allowed.  If you have to handle POSTs as well, I see the 
following options as of now:

1. Use proxy_pass to another server{} in location @502 and process 
   it there.  You may also use proxy_method/proxy_pass_request_body
   to simplify things.

2. Use some normally impossible location, like

    location / {
        proxy_pass http://backend;
        error_page 502 //502.html;
    }

    location = //502.html {
        root /var/www;
    }

The (2) is more like a hack, but should work as //502.html isn't 
normally reachable via nginx due to merge_slashes being "on" by 
default (see http://nginx.org/r/merge_slashes).

Maxim Dounin



More information about the nginx mailing list