Nginx通过代理redirect,重写和保留URL

在Nginx中,我们一直试图redirect一个URL,如下所示:

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

用户仍然可以在浏览器中看到原始url。 一旦用户被redirect,说他们点击链接到/section/index.html ,我们希望这做一个请求,导致redirect

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

并再次保留原来的url。

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

  • 它不会正确执行重写,因为Web服务器http://192.168.1.24收到的请求URL包含/some/path ,因此无法提供所需的页面。
  • 一旦提供页面,当您将鼠标hover在链接上时,该URL中将缺less/some/path

     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; } } 

我们正在寻找一个解决scheme,只涉及到更改example.com上的Web服务器configuration。 我们可以改变192.168.1.24 (也是Nginx)上的configuration,但是我们想要避免这种情况,因为我们需要为通过example.com访问的数百个不同的服务器重复这个设置。

    首先,你不应该在位置块内使用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之前的部分捕获到$ sectionvariables中,然后用于设置proxy_pass目的地。 如果您需要,可以使正则expression式更具体。

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

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

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

    当这个斜杠被添加到一个nginx代理jenkins,你会看到“看来,你的反向代理设置是坏的”错误。

     proxy_pass http://localhost:8080/; Remove this -----------------------------^ 

    它应该阅读

     proxy_pass http://localhost:8080; 

    您可以使用以下configuration在前端和/后端上的/some/path/之间build立100%的无缝映射。

    请注意,这是迄今为止唯一的答案,如果浏览器发送了正确的HTTP Referer头文件,那么也可以无缝地处理产生404 Not Found错误的绝对path,所有这些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存储库中find完整的概念certificate和最小可行产&#x54C1; 。

    这是一个testing运行,以确认所有边缘案例似乎工作:

     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如果你有很多不同的path来映射,那么你可能不想使用基于全局的map指令,而是在location @404if内进行$http_referer的正则expression式比较。

    还要注意的是, proxy_pass中的尾部斜杠以及它所在的location 都是相当重要的 。

    参考文献: