我在设置条件重写方面遇到了麻烦,而且我一直在尝试使用if
指令(尽管所有消息来源都指出了它"'s" evil&#34 ;)使用-f
开关检查是否存在文件,但它无法正常工作。我相信问题/案例最好用例子来解释,所以这里有:
workspace/
myapp/
webroot/
index.php
assets/
baz.js
hello/
foo.js
modules/
hello/
assets/
foo.js
bar.js
/ => /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
总结:
foo.js
仅出现在modules/hello/assets
文件夹中,并从那里发送。bar.js
出现在webroot/assets/hello
和modules/hello/assets
中,并从webroot
发送。
(它隐藏/覆盖modules
)baz.js
仅出现在webroot/assets
中,并从那里发送。现在不能正常工作的部分是:
location /assets/ {
if (-f $uri) {
break;
}
root /workspace/myapp/modules;
rewrite ^/assets/([^/]+)/(.*)$ /$1/assets/$2 break;
}
即if
指令似乎没有任何影响 - bar.js
文件来自modules
而不是webroot
。
我应该使用if
吗?
我有什么办法可以用try_files
来解决这个问题吗?我似乎无法理解这与rewrite
一起工作的方式,而这似乎无法解决。
请不要建议使用部署脚本或其他东西重新组织资产 - 出于各种其他原因,它不是一种选择。
之前我曾在Apache中使用过这种模式,NGINX在大多数方面似乎更有能力,所以我确定这一定是可能的吗?
一个绝对的要求是,我 能够覆盖modules/hello/assets/foo.js
webroot/assets/hello/foo.js
- 来自{{{然而,1}}是一项要求。
答案 0 :(得分:2)
答案分为两部分:第一部分解释了为什么您的配置不起作用,第二部分提供了如何解决问题的示例。如果您只对解决方案感兴趣,请直接进入第二部分。
问题
首先,请注意root
块中location
指令的位置并不重要。如果将它放在location
的顶部或底部并不重要,它会影响整个location
。另外,请记住,break
行末尾的rewrite
告诉Nginx保持在当前位置,即使URI已成功重写。
话虽如此,让我们看一下您的配置,看看Expected results
的每个请求是如何处理的,以及为什么没有按预期工作。
我们假设您的配置中没有其他合适的location
具有更高的优先级。由于Expected results
的每个请求都以/assets
开头,因此所有请求都将根据您location
中提供的规则进行处理。所以:
/assets/hello/foo.js
root
设置为/workspace/myapp/modules
。 if
指令将被评估为false,因为/assets/hello/foo.js
不存在,因此break
将不会被执行。最后,最后rewrite
会将请求的URI从/assets/hello/foo.js
更改为/hello/assets/foo.js
,而后面的break
会告诉Nginx保持在当前location
范围内。因此,/workspace/myapp/modules/hello/assets/foo.js
将被提供。
/assets/hello/bar.js
此请求的处理方式与上一个请求完全相同,因此/workspace/myapp/modules/hello/assets/bar.js
将会提供。{/ p>
/assets/baz.js
同样,root
设置为/workspace/myapp/modules
,if
评估为false。但是这次最终rewrite
不会更改URI,因为请求与正则表达式不匹配。因此,Nginx将尝试提供/workspace/myapp/modules/assets/baz.js
,因为不存在此类文件,将返回404。
正如您所看到的,您的配置可能无法正常工作,原因如下:
if
始终被评估为false,因为您尝试检查URI而不是文件; break
行中rewrite
留在那里; root
始终在此位置设置为/workspace/myapp/modules
,因此无法从其他任何位置投放任何文件。解决方案
最简单的解决方案是使用try_files
:
root /workspace/myapp/webroot;
location /assets/ {
try_files $uri @modules;
}
location @modules {
root /workspace/myapp/modules;
rewrite ^/assets/([^/]+)/(.*)$ /$1/assets/$2 break;
}
此配置告诉Nginx首先在webroot
文件夹中查找文件,如果没有找到,则转到另一个位置的modules
文件夹。这种方法被认为是最可取的。
另一方面,使用if
可以让您在一个位置解决问题:
location /assets/ {
root /workspace/myapp; # The parent folder
if (-f $document_root/webroot/$uri) {
rewrite ^(.*)$ /webroot/$1 break;
}
rewrite ^/assets/([^/]+)/(.*)$ /modules/$1/assets/$2 break;
}
但是,建议不要使用此方法过时。