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

Ian*_*anG 62 nginx

我习惯使用Apache和mod_proxy_html,并试图用NGINX实现类似的功能.具体的用例是我在根上下文服务器上的端口8080上运行Tomcat中的管理UI:

http://localhost:8080/
Run Code Online (Sandbox Code Playgroud)

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

http://localhost:80/admin/
Run Code Online (Sandbox Code Playgroud)

我希望以下超级简单的服务器块可以做到这一点,但它并不完全:

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

    location /admin/ {
        proxy_pass http://localhost:8080/;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

我如何在NGINX中执行此操作?

Day*_*ayo 89

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

传递给上游服务器的URI是根据"proxy_pass"指令是否与URI一起使用来确定的.proxy_pass指令中的尾部斜杠表示URI存在且等于/.尾部斜杠的缺席意味着缺少帽子URI.

带URI的Proxy_pass:

location /some_dir/ {
    proxy_pass http://some_server/;
}
Run Code Online (Sandbox Code Playgroud)

有了上面的代码,有以下代理:

http:// your_server/some_dir/ some_subdir/some_file ->
http:// some_server/          some_subdir/some_file
Run Code Online (Sandbox Code Playgroud)

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

没有URI的Proxy_pass:

location /some_dir/ {
    proxy_pass http://some_server;
}
Run Code Online (Sandbox Code Playgroud)

使用第二个(没有尾部斜杠):代理如下:

http:// your_server /some_dir/some_subdir/some_file ->
http:// some_server /some_dir/some_subdir/some_file
Run Code Online (Sandbox Code Playgroud)

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


因此,在您的情况下,似乎您应该删除尾随斜杠以获得您想要的.


警告

请注意,只有在proxy_pass中不使用变量时,自动重写才有效.如果你使用变量,你应该自己重写:

location /some_dir/ {
  rewrite    /some_dir/(.*) /$1 break;
  proxy_pass $upstream_server;
}
Run Code Online (Sandbox Code Playgroud)

还有其他情况下重写不起作用,这就是为什么阅读文档是必须的.


编辑

再次阅读你的问题,似乎我可能错过了你只想编辑html输出.

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

location /admin/ {
    proxy_pass http://localhost:8080/;
    sub_filter "http://your_server/" "http://your_server/admin/";
    sub_filter_once off;
}
Run Code Online (Sandbox Code Playgroud)

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

  • 为了允许重写除 `text/html` mimetype 之外的内容,我还必须添加 `sub_filter_types *;`。 (3认同)
  • 谢谢,这很有帮助。我认为sub_filter可以做到。 (2认同)
  • 我很好奇nginx已经在多大程度上重写了输出,它是否必须至少在链接中重写主机/主机名?所以,例如,你不会`sub_filter"http:// localhost /""http:// localhost/admin /"` (2认同)
  • 您可能还需要添加 `proxy_redirect` 指令,以便响应发送的 `Location` 标头也根据 url 进行修改。查看本教程:https://www.cyberciti.biz/faq/proxy_redirect-change-replace-location-refresh-response-headers/ (2认同)

小智 17

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

proxy_set_header Accept-Encoding "";
Run Code Online (Sandbox Code Playgroud)

否则它可能无法正常工作.对于您的示例,它将如下所示:

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;
}
Run Code Online (Sandbox Code Playgroud)


Ale*_*kin 6

您可以使用以下 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;
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 为什么这被否决了?代码有问题吗?对我来说,这似乎是一个很好而复杂的解决方案,解决了稍后弹出的代理应用程序的一些警告。但不确定为什么“proxy_redirect off;”。另外我会添加`proxy_set_header X-Forwarded-Proto $scheme;`。 (3认同)