0

I want to get a dynamic 404 response depending on the requested url:

foo.jpg doesn't exist

http://example.com/img/style/thumbnail/foo.jpg  

should show

http://example.com/img/notfound/thumbnail.jpg  

with a 404 header status

I got the rewriting part right, but i can't seem to get it return with a 404 status code.
I tried this with the following code, but without success:

location ~ /img {
    if (!-f $request_filename){
            rewrite "^(.*img\/)style\/([a-zA-Z\_\-[0-9]*)\/?(.+)" $1notfound/$2.jpg;
            #so far so good. Now i want to return the rewrite result as a 404 response
            error_page 404 = $request_filename;
            return 404;
    }
}

This gives me the default nginx 404 error page instead of the rewritten url with 404 status code. How can i tell nginx to use the rewrite result as 404 error page?

jan
  • 118
  • 1
  • 3

2 Answers2

4

You have misunderstood the $request_filename variable. It represents the physical path mapped to the file considering root and alias directives values and the current URI being processed.

So your error_page directive will internally redirect to a URI corresponding to a physical path that doesn't exist as it the same as the path tested to enter your if block.

Operator = in error directive is not an issue, it simply tells nginx to keep the current error code as it is. You are also escaping some symbols in your regex that you don't need to and it hurts readability.

So, your if block does exactly what location blocks do with regular expressions.

You could simply reduce that to :

location /img {

    location ~ ^/img/style/([_-a-zA-Z0-9]*) {
        error_page 404 /img/notfound/$1.jpg;
    }

}
Xavier Lucas
  • 12,815
  • 2
  • 44
  • 50
  • Thanks. This is what i was looking for. I didn't know i could use regex backreferences from location blocks like this. – jan Sep 24 '14 at 13:59
1

I think error_page 404 = $request_filename;

should be

error_page 404 $request_filename;

according to ngx_http_core_module documentation

If your file doesn't exists, it should return the default 404 and not a 200.

Just tell nginx to return this file for all 404 errors.

This code should be placed above your conditional and in your location block:

location ~ /img {
    error_page 404 /srv/www/static/img/notfound.jpg;

    if (!-f $request_filename){
lovethebomb
  • 268
  • 1
  • 2
  • 8
  • I have tried your solution, but i still get the default nginx 404 page. Possibly because $request_filename is the foo.jpg (unexisting image) url when used above the conditional and in the location block. – jan Sep 24 '14 at 11:58
  • After a few more attempts, i used your answer and replaced `error_page 404 $request_filename;` with `error_page 404 $uri;` and that did the trick for me, but i have no idea why. Any ideas? – jan Sep 24 '14 at 12:45
  • 1
    woops! I forgot to actually place the error_page directive! But @Xavier gave the correct answer, kudos to him! ;) – lovethebomb Sep 24 '14 at 14:09