我有一个网络应用程序(由不同的团队编写),附带一个nginx配置代码段来提供重写:
rewrite ^list /ctrl/list.php last;
rewrite ^new /ctrl/new.php last;
然后,该片段可以包含在nginx配置中的服务器块中:
server {
server_name ...;
include /path/to/snippet;
}
不幸的是,只有在docroot中托管应用程序时,这才有效。即使重写在location
区块......
server {
server_name ...
location /subdir/ {
include /path/to/subdir/snippet
}
}
...它不起作用,因为rewrite
的正则表达式和替换仍然相对于docroot。当然,因为应用程序文件对/subdir/
一无所知,所以它不能包含在重写中。
我不知何故需要告诉nginx“处理相对于该子目录的所有以下重写”。
我可以请求其他团队在重写中包含某种变量,但据我所知,nginx在其配置中没有任何类型的宏扩展。
当应用程序托管在Apache上时,它可以与相应的.htaccess文件一起使用,因为.htaccess中的重写是相对于.htaccess文件的位置的。不过,我非常想使用nginx。
答案 0 :(得分:0)
要做到这一点而不重新编译nginx,我想出了一个相当笨拙的解决方法。只有在实际在子目录位置使用include时才需要它 - 当应用程序安装在服务器块的根目录中时,可以包含include。
我们的想法是首先将没有子目录的位置块的每个URI重写为自身,然后应用包含的重写规则,最后将它们重写回子目录路径:
server {
server_name ...
# This has to be a regex check because they run first:
location ~ ^/subdir/ {
rewrite ^/subdir/(.*) /$1;
include /path/to/subdir/snippet
}
...
之后,必须通过每个最终位置块中的额外重写来取消初始重写。此重写设置了break
标志,以确保不会再次尝试前一个块(导致无限循环运行10次):
location / {
root /var/www;
rewrite ^(.*) /subdir$1 break;
}
location ~ \.php$ {
proxy_pass http://127.0.0.1;
rewrite ^(.*) /subdir$1 break;
}
我还没有尝试过,但是应该可以通过重新编译nginx来添加一个客户模块(所有nginx模块都已编译)来获得更清洁的解决方案。这是not too hard to do on Ubuntu。
即使没有重新编译,也可以使用变量将子目录添加到重写指令的替换部分,因此困难的部分是将其添加到正则表达式。 ngx_http_rewrite
模块实际上不执行正则表达式匹配,而只是将其编译为ngx_http_script_regex_start_code
模块的指令(ngx_http_script
)。正则结构上的sets the uri=1
parameter,它告诉ngx_http_script
模块请求use the current URI。
因此,应该可以将当前位置前缀添加到模式中,或者在匹配之前将其从URI中删除。