使Nginx重写相对 [英] Make nginx rewrite relative

查看:90
本文介绍了使Nginx重写相对的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Web应用程序(由不同的团队编写),该Web应用程序带有一个nginx配置片段以提供重写:

I have a web application (written by a different team) that comes with an nginx config snippet to provide rewrites:

rewrite ^list /ctrl/list.php last;
rewrite ^new /ctrl/new.php last;

然后可以将此片段包含在Nginx配置中的服务器块中:

This snippet can then be included in a server block in the nginx config:

server {
  server_name ...;

  include /path/to/snippet;
}

不幸的是,仅当应用程序托管在docroot中时,此方法才有效.即使重写是在location块中...

Unfortunately this only works as long as the application is hosted in the docroot. Even when the rewrites are in a location block...

server {
  server_name ...

  location /subdir/ {
    include /path/to/subdir/snippet
  }
}

...它不起作用,因为rewrite regex replacement 仍然相对于文档根目录.当然,由于应用程序文件对/subdir/一无所知,因此它不能包含在重写中.

... it does not work because both regex and replacement of rewrite are still relative to the docroot. Of course since the applications files don't know anything about /subdir/ it cannot be included in the rewrites.

我不知何故需要告诉nginx处理相对于此子目录的以下所有重写".

I somehow need to tell nginx to "treat all of the following rewrites relative to this subdirectory".

我可以要求其他团队在重写中包含某种变量,但是据我了解,nginx在其配置中没有任何种类的宏扩展.

I could request the other team to include some kind of variable in the rewrites, but as far as I understand nginx doesn't have any kind of macro expansion in its config.

当应用程序托管在Apache上时,它可以与相应的.htaccess文件一起正常工作,因为.htaccess中的重写是相对于.htaccess文件的位置而言的.不过,我还是非常想使用nginx.

When the application is hosted on Apache, it works fine with the corresponding .htaccess file, because the rewrites in .htaccess are relative to the location of the .htaccess file. Still, I'd very much like to use nginx.

推荐答案

要做到这一点而无需重新编译nginx,我想出了一个相当笨拙的解决方法.仅当在一个子目录位置实际使用include时才需要-当应用程序安装在服务器块的根目录中时,include就可以包含在内.

To do it without recompiling nginx, I came up with a rather clumsy workaround. It's only needed when the include is actually used in a subdir location - when the application is installed in the root of the server block, the include can just be included.

想法是先将该位置块的每个URI重写为自身,而没有子目录,然后应用包含的重写规则,最后将它们重写回子目录路径:

The idea is to first rewrite every URI of that location block to itself without the subdir, then apply the included rewrite rules and finally rewrite them back to the subdir path:

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次的无限循环):

Afterwards the initial rewrite has to be canceled by an additional rewrite in every final location block. This rewrite has the break flag set to make sure that the previous block won't be tried again (leading to an infinite loop that is run 10 times):

  location / {
    root   /var/www;

    rewrite ^(.*) /subdir$1 break;
  }

  location ~ \.php$ {
    proxy_pass   http://127.0.0.1;

    rewrite ^(.*) /subdir$1 break;
  }


我还没有尝试过,但是应该可以通过重新编译nginx来添加一个custome模块(所有nginx模块都被编译进来)来获得更干净的解决方案.这是在Ubuntu上不太难.

即使不重新编译,也可以使用变量将子目录添加到 rewrite 指令的 replacement 部分中,所以最困难的部分是将其添加到正则表达式模式. ngx_http_rewrite模块实际上并不执行正则表达式匹配,而只是将其编译为ngx_http_script模块的指令(ngx_http_script_regex_start_code).它设置uri=1参数在正则表达式结构上,它告诉ngx_http_script模块使用请求的当前URI .

Even without recompiling it would be possible to add the subdirectory to the replacement part of the rewrite directive using a variable, so the hard part is to add it to the regex pattern. The ngx_http_rewrite module does not actually perform the regex matching but merely compiles it into an instruction (ngx_http_script_regex_start_code) for the ngx_http_script module. It sets the uri=1 parameter on the regex struct, which tells the ngx_http_script module to use the current URI of the request.

因此应该可以在匹配之前将当前位置前缀添加到模式中,或将其从URI中删除.

So it should be possible to either add the current location prefix to the pattern or remove it from the URI before matching.

这篇关于使Nginx重写相对的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆