使nginx相对重写

时间:2013-12-27 05:18:20

标签: nginx

我有一个网络应用程序(由不同的团队编写),附带一个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。

1 个答案:

答案 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中删除。