Nginx 通过代理重定向、重写并保留 URL

Nginx 通过代理重定向、重写并保留 URL

在 Nginx 中我们尝试重定向 URL 如下:

http://example.com/some/path -> http://192.168.1.24

用户在浏览器中仍会看到原始 URL。一旦用户被重定向,比如他们点击了 的链接/section/index.html,我们希望它发出一个导致重定向的请求

http://example.com/some/path/section/index.html -> http://192.168.1.24/section/index.html

并再次保留原始 URL。

我们尝试了各种使用代理和重写规则的解决方案,下面显示了最接近解决方案的配置(请注意,这是 Web 服务器的 Web 服务器配置example.com)。但是,这仍然存在两个问题:

  • 它没有正确地执行重写,因为 Web 服务器收到的请求 URLhttp://192.168.1.24包含所需的页面/some/path,因此无法提供所需的页面。
  • 当您将鼠标悬停在页面已提供的链接上时,/some/pathURL 中缺少

    server {
        listen          80;
        server_name     www.example.com;
    
        location /some/path/ {
            proxy_pass http://192.168.1.24;
            proxy_redirect http://www.example.com/some/path http://192.168.1.24;
            proxy_set_header Host $host;
        }
    
        location / {
            index index.html;
            root  /var/www/example.com/htdocs;
        }
    }
    

我们正在寻找一种仅涉及更改 Web 服务器配置的解决方案example.com。我们能够更改配置192.168.1.24(也包括 Nginx),但是我们希望尽量避免这种情况,因为我们需要对数百台通过代理访问的不同服务器重复此设置example.com

答案1

首先,您不应该root在位置块内使用指令,这是一种不好的做法。不过在这种情况下,这并不重要。

尝试添加第二个位置块:

location ~ /some/path/(?<section>.+)/index.html {
    proxy_pass http://192.168.1.24/$section/index.html;
    proxy_set_header Host $host;
}

这会将 /some/path/ 之后和 index.html 之前的部分捕获到 $section 变量中,然后使用该变量设置 proxy_pass 目标。如果需要,您可以使正则表达式更具体。

答案2

您应该使用 URI 部分proxy_pass指令。此外,您混淆了proxy_redirect指令的顺序参数,可能您根本不需要它。Nginx 为该指令提供了合理的默认值。

在这种情况下,你的location块可能非常简单:

location /some/path/ {
    proxy_pass http://192.168.1.24/;
    # note this slash  -----------^
    proxy_set_header Host $host;
}

答案3

/some/path/您可以使用以下配置在前端和/后端之间实现 100% 无缝映射。

请注意,这是迄今为止唯一的答案,404 Not Found只要Referer浏览器发送了正确的 HTTP 标头,它就可以无缝地处理产生错误的绝对路径,因此,所有这些 gif 都应该继续加载,而无需修改底层 HTML(这不仅成本高昂,而且如果没有默认编译的附加模块,也不支持)。

location /some/path/ {
    proxy_pass http://192.168.1.24/; # note the trailing slash!
}
location / {
    error_page 404 = @404;
    return 404; # this would normally be `try_files` first
}
location @404 {
    add_header Vary Referer; # sadly, no effect on 404
    if ($http_referer ~ ://[^/]*(/some/path|/the/other)/) {
        return 302 $1$uri;
    }
    return 404 "Not Found\n";
}

你可以找到完整的概念验证和最小可行产品https://github.com/cnst/StackOverflow.cnst.nginx.conf存储库。

以下进行测试以确认所有边缘情况均有效:

curl -v -H 'Referer: http://example.su/some/path/page.html' localhost:6586/and/more.gif | & fgrep -e HTTP/ -e Referer -e Location
> GET /and/more.gif HTTP/1.1
> Referer: http://example.su/some/path/page.html
< HTTP/1.1 302 Moved Temporarily
< Location: http://localhost:6586/some/path/and/more.gif
< Vary: Referer

curl -v localhost:6586/and/more.gif | & fgrep -e HTTP/ -e Referer -e Location
> GET /and/more.gif HTTP/1.1
< HTTP/1.1 404 Not Found

curl -v localhost:6586/some/path/and/more.gif | & fgrep -e HTTP/ -e Referer -e Location -e uri
> GET /some/path/and/more.gif HTTP/1.1
< HTTP/1.1 200 OK
request_uri:    /and/more.gif

PS 如果您有很多不同的路径需要映射,那么您可能不想$http_referer在 withinif中进行正则表达式比较location @404,而是想要使用基于全局的map指令。

proxy_pass还请注意, 以及它所location包含的中的尾部斜杠,根据相关答案非常重要

参考:

答案4

当该斜线添加到 nginx 代理的 jenkins 时,您会看到“看来您的反向代理设置已损坏”错误。

proxy_pass          http://localhost:8080/;

Remove this -----------------------------^

应该读作

proxy_pass          http://localhost:8080;

相关内容