如何在 NGINX 的代理响应中重写 URL
Posted
技术标签:
【中文标题】如何在 NGINX 的代理响应中重写 URL【英文标题】:How do I rewrite URLs in a proxy response in NGINX 【发布时间】:2015-12-09 03:00:46 【问题描述】:我习惯于将 Apache 与 mod_proxy_html 一起使用,并且正在尝试使用 nginx 实现类似的功能。具体用例是我在 Tomcat 中在根上下文的服务器上的 8080 端口上运行了一个管理 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 重写为以 /admin/ 而不是 / 开头。
我如何在 NGINX 中做到这一点?
【问题讨论】:
【参考方案1】:如果没有需要用sub_filter重写的超链接,
你可能只使用proxy_redirect
指令:
location /admin/
proxy_pass http://localhost:8080/;
proxy_redirect / /admin/
它根据给定的'match-rewrite'规则更改响应的Location-Header。
【讨论】:
【参考方案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;
【讨论】:
为什么会被否决?代码有问题吗?对我来说似乎是一个不错且复杂的解决方案,解决了代理稍后弹出的应用程序的一些警告。不知道为什么proxy_redirect off;
。另外我会添加proxy_set_header X-Forwarded-Proto $scheme;
。
> 问题是返回的内容 (html) 包含所有在根上下文中访问的脚本和样式信息的 URL,因此我需要重写这些 URL 以改为以 /admin/ 开头的 /。至少在发布此评论时,它不满足此要求。【参考方案3】:
我们应该先仔细完整地阅读the documentation on proxy_pass。
传递给上游服务器的 URI 取决于“proxy_pass”指令是否与 URI 一起使用。 proxy_pass 指令中的尾部斜杠表示 URI 存在且等于 /
。没有尾部斜杠意味着不存在帽子 URI。
带有 URI 的代理通行证:
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 的代理通行证:
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;
基本上就是要替换的字符串和替换字符串
【讨论】:
谢谢,这很有帮助。我认为 sub_filter 会做到的。 我很好奇 nginx 已经在多大程度上重写了输出,难道它不需要至少在链接中重写主机/主机名吗?例如,你不会sub_filter "http://localhost/" "http://localhost/admin/"
为了允许重写text/html
mimetype 以外的其他类型,我还必须添加sub_filter_types *;
。
这个解决方案对我来说发生了一些奇怪的事情。资源(*.js、*.css 等正在获取),但页面无法加载。我希望http://your_server/admin/
在proxy_pass 期间被解析为http://your_server
,但它没有,我在我的应用程序中收到错误react-router /admin/ location did not match any routes
,因为我的应用程序对'/admin'一无所知。
非常感谢您对带有URI的proxy_pass的解释,这解决了我的问题(/)【参考方案4】:
对于具有数据压缩的后端服务器,您可能还需要在第一个“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;
【讨论】:
顺便说一句:对于正则表达式检查subs_filter
(是的,还有另一个s
)。以上是关于如何在 NGINX 的代理响应中重写 URL的主要内容,如果未能解决你的问题,请参考以下文章
nginx rewrite url重写, if,负载均衡 ,nginx反向代理配置