Nginx location match all file extensions except php

后端 未结 1 1803
南笙
南笙 2021-01-12 17:21

I have the following in my nginx config file, it works, but I don\'t want to have to list every file extension.

location ~ \\.(gif|jpg|png|css|js|ttf|woff|ht         


        
相关标签:
1条回答
  • 2021-01-12 17:59

    The PCRE Library

    Nginx uses the PCRE library written in C. There's a huge man page, a bit hard to understand sometimes but quite detailed. Among it, you will find the look ahead / look behind functionnalities as you would find them in Perl.

    Postive/negative look ahead/behind

    Positive/negative look ahead/behind allow to match a string if one part of it is/isn't followed/preceded by an expression. Look behind expressions are restricted to a fixed string because it's not possible for most implementations to apply a regular expression backwards as you need to know how many steps you go back for this. Look ahead doesn't obviously suffer from this limitations, so you can use a regular expression like you usually do.

    Here's the relevant section of the man page :

    LOOKAHEAD AND LOOKBEHIND ASSERTIONS

         (?=...)         positive look ahead
         (?!...)         negative look ahead
         (?<=...)        positive look behind
         (?<!...)        negative look behind
    
     Each top-level branch of a look behind must be of a fixed length.
    

    Unfortunately you can't capture the end of the string with look ahead.

    Look behind in action

    So, our first attempt will be using negative look behind from the end of the string :

    location ~ .+(?<!\.php)$ {
        ...
    }
    

    Which means "Only capture strings that don't end with .php". That's quite close from what we need already. But there's something more to add to make it work like expected.

    Nested locations

    Indeed, nothing guarantees that you will have a string containing a file extension at this point. It could rather be anything except ^.+\.php$. To make sure this is a real file suffix, the natural way to overhaul this limit is by using nested location blocks where the most restrictive part is the apex. So our configuration will now look like below.

    location ~ .+(?<!\.php)$ {
        location ~ ^[^.]+\.[^.]+$ {
            try_files $uri /images/default.gif;
        }
    }
    

    And that's it !

    Your second issue

    Here are my remarks after your post update for the second issue you are facing (404 errors on other URLs).

    As ~ .+(?<!\.php)$ matches everything except \.php$ and locations are nested, you need to nest the location block / and transform it to a regex match :

    location ~ .+(?<!\.php)$ {
    
        location ~ ^[^.]+\.[^.]+$ {
            try_files $uri /images/default.gif;
        }
    
        location ~ / {
            # your stuff
        }
    
    } 
    

    Also note that you can end up with an infinite loop with the try_files $uri /images/default.gif; part because the last paremeter of the try_files directive is an internal redirect or an HTTP code. So if /images/default.gif doesn't resolve to a file, the request will go trough this location block 10 more times until nginx stops the processing and return HTTP 500. So change it to try_files $uri /images/default.gif =404;.

    0 讨论(0)
提交回复
热议问题