如何让 nginx 重写 HTTP 主体内容中的 URI?

如何让 nginx 重写 HTTP 主体内容中的 URI?

这是我之前关于如何使 nginx 反向代理 302 重定向到 URI 子文件夹而不是根文件夹

我有一个 nginx 代理服务器,它使用rewriteproxy_pass指令将外部请求代理到 URL,例如https://domain.com/my/web/app/内部 LAN 服务器https://10.0.0.22/。这是我尝试用 ASCII UML 表示翻译:

                                    .-------------.       .------------------.
                                    | Nginx proxy  |      | Local web server |
                                    | (domain.com) |      | (10.0.0.22)      |
                                    '-------------'       '------------------'
                                               |                 |
                                               |                 |
GET https://domain.com/my/web/app/ ----------->|                 |
                                               |---------------->| GET /
                                               |                 |
                                               |<----------------| 302 redirect /login.php
302 redirect /my/web/app/login.php <-----------|                 |
                                               |                 |
GET https://domain.com/my/web/app/login.php -->|                 |
                                               |---------------->| GET /login.php
                                               |                 |
                                               |<----------------| 200
HTML body content (images, CSS, links) <-------|

这是我的 nginx 配置文件中的实际位置块:

location ^~ /my/web/app/
{
    proxy_buffering   off;
    rewrite           /my/web/app/(.*) /$1 break;
    proxy_pass        https://10.0.0.22/;
    proxy_redirect    default;
}

它非常适合 HTTP 请求和响应的内部和外部 URI 路径之间的 URI 转换,但 HTML 内容(正文图像、CSS、脚本)中的任何 URI 都无法转换。

例如,HTML 响应中嵌入了相对路径的图像(其 URI 如 /images/logo.png)会被传回至 Web 客户端并被解释为https://domain.com/images/logo.png而不是https://domain.com/my/web/app/images/logo.png

我可以理解为什么会发生这种情况,但如果有一种方法可以动态代理内容和请求,那就太好了。有没有办法让 nginx 也转换嵌入在 HTML 内容中的 URI?当 HTML 内容通过代理服务器时,是否可以动态解析和更新 HTML 内容?

答案1

到目前为止,我发现的唯一解决办法是HttpSubs模块(另见github 页面)。

该模块不是官方 Nginx 源的一部分,因此您可能需要自己构建 Nginx 才能使用该模块。

答案2

使用ngx_http_sub_module,可以执行以下操作(添加到上面的配置示例中,紧接着指令proxy_pass):

    sub_filter_once off;
    sub_filter ' href="/' ' href="/my/web/app/';
    sub_filter ' src="/' ' src="/my/web/app/';
    sub_filter ' action="/' ' action="/my/web/app/';

这应该可以替换各种上下文中的链接 URL(<a href=、、、、等等) <img src=,将以get开头的<link href=任何内容替换为。<script src=<form action=///my/web/app/

第一行告诉它在第一个匹配之后继续扫描(这对于获取结果 HTML 中的每个链接至关重要);其他三行更新各种形式的链接和资源标识符。

如果您的服务器确实重定向,您可能还需要以下一项或多项(您可能只需要一项,但哪一项取决于应用程序的行为):

    proxy_redirect / /my/web/app/; # for redirects just using /
    proxy_redirect https://10.0.0.22/ /my/web/app/; # redirects using backend url
    proxy_redirect https://$http_host/ /my/web/app/; # proxy-aware (see below)

请注意第三项:至少在我使用的环境中(测试 rails 应用程序,使用 http - 因此与您的有点不同),该应用程序(Rails)正在生成一个使用我传入的标头Location:的标头(我因为其他原因需要它),所以它看起来像:;因此,第三行就是我需要使用的,这样我就可以匹配并将其替换为。Hostproxy_set_headerLocation: https://example.com/somethinghttps://example.com//my/web/app/

(在我看来,我似乎在某处看到过另一个可以设置的标头,它会让应用程序知道基本 URL 预代理,这可能使这个不再是必需的......但我刚才没能找到它,而且这对我有用,所以......)

相关内容