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 inmodules/hello/assets
folder , gets delivered there.bar.js
present both inwebroot/assets/hello
,modules/hello/assets
, gets deliveredwebroot
. (it hides/overrides file inmodules
)baz.js
present inwebroot/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:
/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.
/assets/hello/bar.js
this request processed same way previous one, /workspace/myapp/modules/hello/assets/bar.js
served.
/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
inrewrite
line; root
set/workspace/myapp/modules
in location no file can served anywhere else.
the solutions
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 gomodules
folder in location. approach considered preferable.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
Post a Comment