如何在NGINX中的代理响应中重写URL


86

我习惯将Apache与mod_proxy_html一起使用,并且试图通过NGINX实现类似的功能。特定的用例是,我在根上下文的服务器上的端口8080上的Tomcat中运行了一个管理UI:

http://localhost:8080/

我需要在端口80上显示它,但是我在此主机上运行的NGINX服务器上还有其他上下文,因此想尝试在以下位置访问它:

http://localhost:80/admin/

我希望下面的超级简单服务器块可以做到,但事实并非如此:

server {
    listen  80;
    server_name screenly.local.akana.com;

    location /admin/ {
        proxy_pass http://localhost:8080/;
    }
}

问题在于返回的内容(html)包含指向脚本和样式信息的URL,这些URL都可以在根上下文中访问,因此我需要重写这些URL,使其以/ admin /而不是/开头。

如何在NGINX中做到这一点?

Answers:


121

首先,我们应该仔细并完整地阅读proxy_pass上的文档

根据是否将“ proxy_pass”指令与URI一起使用来确定传递给上游服务器的URI。proxy_pass指令中的尾部斜杠表示URI存在且等于/。尾部没有斜杠表示没有帽子URI。

具有URI的Proxy_pass

location /some_dir/ {
    proxy_pass http://some_server/;
}

有了以上内容,就有以下代理:

http:// your_server/some_dir/ some_subdir/some_file ->
http:// some_server/          some_subdir/some_file

基本上,/some_dir/被替换/为将请求路径从更改/some_dir/some_subdir/some_file/some_subdir/some_file

不带URI的Proxy_pass

location /some_dir/ {
    proxy_pass http://some_server;
}

第二个(不带斜杠):代理如下:

http:// your_server /some_dir/some_subdir/some_file ->
http:// some_server /some_dir/some_subdir/some_file

基本上,完整的原始请求路径无需更改就可以传递。


因此,就您的情况而言,似乎您应该只添加斜杠以获取所需的内容。


警告

请注意,仅当您在proxy_pass中不使用变量时,自动重写才有效。如果使用变量,则应该重写自己:

location /some_dir/ {
  rewrite    /some_dir/(.*) /$1 break;
  proxy_pass $upstream_server;
}

在其他情况下,重写将不起作用,这就是为什么必须阅读文档的原因。


编辑

再次阅读您的问题,似乎我可能想念您只想编辑html输出。

为此,您可以使用sub_filter指令。就像是 ...

location /admin/ {
    proxy_pass http://localhost:8080/;
    sub_filter "http://your_server/" "http://your_server/admin/";
    sub_filter_once off;
}

基本上,您要替换的字符串和替换字符串


2
谢谢,这很有帮助。我认为sub_filter可以做到。
IanG

2
我很想知道nginx已经在多大程度上重写了输出,是否不必至少在链接中重写主机/主机名?因此,例如,您不是吗?sub_filter "http://localhost/" "http://localhost/admin/"
-ThorSummoner

1
为了允许重写text/htmlmimetype之外的其他内容,我还必须添加sub_filter_types *;
anttikoo

这个解决方案对我来说有点奇怪。资源(* .js,*。css等已获取),但是页面无法加载。我希望在proxy_pass期间http://your_server/admin/能够解决http://your_server该问题,但事实并非如此,并且react-router /admin/ location did not match any routes我的应用程序中出现错误,因为我的应用程序对'/ admin'一无所知。
Prachi

您可能还需要添加proxy_redirect指令,Location以使响应所发送的标头也根据url进行修改。看看这个教程:cyberciti.biz/faq/…–
vivanov

21

对于具有数据压缩功能的后端服务器,您可能还需要在第一个“ sub_filter”之前设置以下指令:

proxy_set_header Accept-Encoding "";

否则可能无法正常工作。以您的示例为例:

location /admin/ {
    proxy_pass http://localhost:8080/;
    proxy_set_header Accept-Encoding "";
    sub_filter "http://your_server/" "http://your_server/admin/";
    sub_filter_once off;
}

-2

您可以使用以下nginx配置示例:

upstream adminhost {
  server adminhostname:8080;
}

server {
  listen 80;

  location ~ ^/admin/(.*)$ {
    proxy_pass http://adminhost/$1$is_args$args;
    proxy_redirect off;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Host $server_name;
  }
}

1
为什么这样投票?代码有问题吗?对我来说,这似乎是一个不错且复杂的解决方案,它解决了代理代理问题的注意事项,这些问题随后会出现。不知道为什么proxy_redirect off;。我还要补充一点proxy_set_header X-Forwarded-Proto $scheme;
LuH
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.