如何在 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如何截取url部分字符并替换,求助

Nginx缓存功能防盗链URL重写

nginx rewrite url重写, if,负载均衡 ,nginx反向代理配置

如何在 nginx 中转换(重写)部分 URL

Nginx之反向代理日志格式集群缓存压缩URl 重写,读写分离配置

如何在 Nginx Regex 中重写 URL 并进行调试?