简体   繁体   中英

How to set Nginx URI to fix empty URI in redirect to named location

The problem: when accessing our website with an invalid URL that contains a '%' sign, Nginx throws a 400 Bad Request error.

Instead of the Nginx page, we would like to rewrite the request to a (WordPress) 404 page.

I have tried the following:

location @400 {
    rewrite ^ /404 break;
}

error_page 400 =307 @400;

However, this generates a 500 Internal Server Error on Nginx.

Nginx error log says: '... empty URI in redirect to named location "@400" while reading client request line..., request: "GET <invalid-url>"'.

This is not unexpected, as the original URL is invalid.

So I guess what I am looking for is to set the URI explicitly for the rewrite. How to do this? Or is there a better approach? I am not that familiar with Nginx.

I had the same objective (return 444 instead of customised error messages) and encountered the same problem using @named_location (for certain weird requests, in particular when no POST/GET/HEAD method set in header, Nginx returned its default 500 error page and the error log reported: empty URI in redirect to named location "@named_location" while reading client request ).

Someone had opened a ticket with Nginx , here's the response:

[...] the problem is that you are trying to redirect errors which appear during early request processing stages - when the request URI is not yet parsed - to a named location. Named locations are designed to preserve existing request URI, and redirecting such an incomplete request to a named location is likely to cause serious problems in other parts of the code. As such, an attempt to do such a redirect results in the "empty URI in redirect to named location" error. This in turn prevents your custom error page from being used, so an internal one is returned. If you want to handle errors which appear during early request processing stages, such as 400 Bad Request, consider using error pages with explicitly set URI. Or you may instead avoid trying to redirect such errors, as this is generally much safer approach. Note well that the fact that server is nginx is not an information leak. It is anyway reported in a number of ways, including the Server response header. If you for ​some reason want to hide nginx version, you can do so via the ​server_tokens directive.

So I changed the error customisation as follows:

error_page 301 400 403 404 500 502 503 504 =444 /444.html;
location = /444.html {
        return 444;
}

# Instead of:
# error_page 301 400 403 404 500 502 503 504 =444 @named_location;
# location @named_locations {
#         return 444;
# }
# which gives the above-mentioned error and returns Nginx's default 500 error page.

This appears to have solved the issue.

According to the documentation the code should be a bit different.

This is the rewriting copied from the documentation:

location /old/path.html {
    error_page 404 =301 http:/example.com/new/path.html;
}

Question is if it will work like this:

location 400 {
    error_page 400 =307 http:/example.com/400.html;
}

... because on the github-page you linked is written:

If something like "error_page 400 @name" is used in a configuration, a request could be passed to a named location without URI set, and this in turn might result in segmentation faults or other bad effects as most of the code assumes URI is set.

With this change nginx will catch such configuration problems in ngx_http_named_location() and will stop request processing if URI is not set, returning 500.

If that's still the current state it would mean a 400 error triggers in nginx a 500 error. Nevertheless I could trigger a 400 error and also deliver a custom 400 page just with this configuration:

error_page 400 /400.html;

So you could also try to configure a custom error 500 page but I never got that running, instead only the common 500er page of nginx was shown.

You can just try it with this configuration

error_page 400 /400.html;
error_page 404 /404.html;
error_page 500 /500.html;

If that's working you can adjust the 3xx code and more like you want it. Surely you can also deliver the 404 error page on a 400 error, but I never succeeded with rewriting the error headers like this:

error_page 404 =301 http:/example.com/new/path.html;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM