conditional rewrite or try_files with NGINX? -


i'm having trouble setting conditional rewrite, , i've been trying use if directive (despite sources indicating it's "evil") -f switch check presence of file, it's not working. believe issue/case best explained example, here goes:

directory structure

workspace/   myapp/     webroot/       index.php       assets/         baz.js         hello/           foo.js     modules/       hello/         assets/           foo.js           bar.js 

expected results

/                     =>  /workspace/myapp/webroot/index.php /assets/hello/foo.js  =>  /workspace/myapp/webroot/assets/hello/foo.js /assets/hello/bar.js  =>  /workspace/myapp/modules/hello/assets/foo.js /assets/baz.js        =>  /workspace/myapp/webroot/assets/baz.js 

in summary:

  • foo.js present in modules/hello/assets folder , gets delivered there.
  • bar.js present both in webroot/assets/hello , modules/hello/assets , gets delivered webroot. (it hides/overrides file in modules)
  • baz.js present in webroot/assets , gets delivered there.

the part doesn't work right now, this:

location /assets/ {     if (-f $uri) {         break;     }     root     /workspace/myapp/modules;     rewrite  ^/assets/([^/]+)/(.*)$ /$1/assets/$2 break; } 

namely if directive, doesn't seem have affect - bar.js file gets delivered modules rather webroot.

should using if or not?

is there way can solve problem try_files instead? can't seem grasp how work rewrite can't seem around.

please not suggest reorganizing assets using deploy script or - it's not option, various other reasons.

i have used pattern apache before, , nginx seems more capable in respects, i'm sure must possible?

one requirement isn't absolute, don't have able override modules/hello/assets/foo.js webroot/assets/hello/foo.js - serving scripts webroot/assets/* requirement.

the answer divided 2 parts: first part explains why configuration not work , second 1 provides examples of how solve problem. if interested in solution, go straight second part.

the problem

first of all, note positon of root directive in location block not important. not matter if put @ top or @ bottom of location, affect whole location anyway. also, keep in mind break in end of rewrite line tells nginx stay within current location if uri has been rewrited.

having said that, let's take @ configuration , see how every request expected results processed , why nothing works expected.

let's presume there no other suitable location higher priority in configuration. since every request expected results starts /assets, of them handled according rules presented in location. so:

  1. /assets/hello/foo.js

the root set /workspace/myapp/modules. if directive evaluated false, because /assets/hello/foo.js not exist , break not executed. finally, last rewrite change requested uri /assets/hello/foo.js /hello/assets/foo.js , following break tell nginx stay within current location. consequence /workspace/myapp/modules/hello/assets/foo.js served.

  1. /assets/hello/bar.js

this request processed same way previous one, /workspace/myapp/modules/hello/assets/bar.js served.

  1. /assets/baz.js

yet again root set /workspace/myapp/modules , if evaluated false. time final rewrite not change uri, because request not match regular expression. consequence nginx try serve /workspace/myapp/modules/assets/baz.js , since there no such file exists, return 404.

as can see configuration cannot possibly work want several reasons:

  • if evaluated false, because try check uris , not files;
  • the request stays within location because tell stay there break in rewrite line;
  • root set /workspace/myapp/modules in location no file can served anywhere else.

the solutions

  1. the easiest solution use try_files:

    root /workspace/myapp/webroot;  location /assets/ {     try_files $uri @modules; }  location @modules {     root     /workspace/myapp/modules;     rewrite  ^/assets/([^/]+)/(.*)$ /$1/assets/$2 break; } 

    this configuration tells nginx file in webroot folder first , if nothing found go modules folder in location. approach considered preferable.

  2. on other hand, using if allow solve problem within 1 location:

    location /assets/ {     root /workspace/myapp; # parent folder      if (-f $document_root/webroot/$uri) {         rewrite ^(.*)$ /webroot/$1 break;     }      rewrite  ^/assets/([^/]+)/(.*)$ /modules/$1/assets/$2 break; } 

    however, approach considered outdated not recommended use.


Comments

Popular posts from this blog

c - Bitwise operation with (signed) enum value -

xslt - Unnest parent nodes by child node -

YouTubePlayerFragment cannot be cast to android.support.v4.app.Fragment -