Nginx try_files gotcha

aliasnginx

Ok – i've been using this rule for a while

location ~* /(?:abc12345|12abcdef)/(.*\.(jpe?g|gif|png)) {
    alias /usr/local/image/$1;
    error_page 404 /handler.php;
}

where if the image file exists, it is served – if the file doesn't exist, a custom 404 error_page named /handler.php works to deliver the goods. if the image was unchanged, it would return a 304 – new images returned a 200. Almost perfect.

Problem is, returning a 404 with the image isn't the proper thing to do – I should accept the request, determine if the file exists, and if not run handler and return the image – and not show a 404.

I've tried to replace error_page with try_files, but am not getting the desired result:

 location ~* /(?:abc12345|12abcdef)/(.*\.(jpe?g|gif|png)) {
     alias /usr/local/image/$1;
     try_files $uri $uri/ /handler.php;
 }

Nothing seems to match in try_files so all requests fall through to handler.php. I understand that alias is a special match pattern, but if I try to enter in

try_files "" /handler.php;

Which works, but the "" returns the incorrect content-type (Content-Type:·application/octet-stream) while handler.php returns the correct one (Content-Type:·image/jpeg)

sure, I could add in "default_type image/jpeg;" to force the default, but I run the risk of returning a jpeg content-type when the actual image could be gif or png.

I'm running debian 6 – nginx-1.0.6-1~dotdeb.2

Any ideas on how to make this work?

Best Answer

The first of all, you could force Nginx to return the status code from your script when using error_page:

location ~* /(?:abc12345|12abcdef)/(.*\.(jpe?g|gif|png)) {
    alias /usr/local/image/$1;
    error_page 404 = /handler.php;
}

That equal sign tells Nginx to return the status code from handler.php instead of 404.

As of try_files, try this config:

location ~* /(?:abc12345|12abcdef)/(.*\.(jpe?g|gif|png)) {
    root /usr/local/image;
    try_files /$1 /handler.php;
}