这是我之前关于如何使 nginx 反向代理 302 重定向到 URI 子文件夹而不是根文件夹。
我有一个 nginx 代理服务器,它使用rewrite
和proxy_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:
的标头(我因为其他原因需要它),所以它看起来像:;因此,第三行就是我需要使用的,这样我就可以匹配并将其替换为。Host
proxy_set_header
Location: https://example.com/something
https://example.com/
/my/web/app/
(在我看来,我似乎在某处看到过另一个可以设置的标头,它会让应用程序知道基本 URL 预代理,这可能使这个不再是必需的......但我刚才没能找到它,而且这对我有用,所以......)