Nginx反向代理+ URL重写


149

Nginx在端口80上运行,我正在使用它来反向代理URL并/foo通过3200以下方式传递端口:

location /foo {
                proxy_pass http://localhost:3200;
                proxy_redirect     off;
                proxy_set_header   Host $host;
}

这可以正常工作,但是我在port上有一个应用程序3200,我不希望将/foo其发送给该应用程序。那就是-当我访问时http://localhost/foo/bar,我只/bar希望成为该应用程序收到的路径。所以我尝试将这行添加到上面的位置块:

rewrite ^(.*)foo(.*)$ http://localhost:3200/$2 permanent;

这将导致302重定向(URL更改),但我要301。我该怎么办?


:如果你有Grafana情况下,任何问题,你应该使用这些配方docs.grafana.org/installation/behind_proxy/...
穆赫辛·赛义德

Answers:


169

从远程系统(例如客户端的Web浏览器)重定向到localhost都没有任何意义。因此,在您的情况下,永久性重写标志(301)或重定向(302)不可用。

请尝试使用透明重写规则进行以下设置:

location  /foo {
  rewrite /foo/(.*) /$1  break;
  proxy_pass         http://localhost:3200;
  proxy_redirect     off;
  proxy_set_header   Host $host;
}

使用curl -i来测试你的重写。对该规则进行非常细微的更改可能会导致nginx执行重定向。


1
当我这样做时,URL路径仍然在我的应用程序中以/ foo开头...
jeffreyveon

肯定有另一个问题。几分钟前,我成功重现了此方案。原始地址:HTTP://开发/富/ TESTME / 1234 -上运行的Apache作为连接代理后端PHP脚本的REQUEST_URI: '/ TESTME / 1234'
延Bradler

9
正则表达式可能应该是/foo(.*),否则example.com/foo将不匹配。(这可能是jeffreyveon所经历的)
Benno

这种工作方式,但我设置为proxy_set_body的身体已被删除。
贾斯汀·托马斯

重写/(.*)/socket.io/ break; 为SOCKET.IO节省我的一天
user956584'7

122

只要在proxy_pass指令中指定URI,简单的位置前缀匹配就可以实现此目的而无需使用重写规则:

location /foo {
  proxy_pass http://localhost:3200/;
}

请注意指令/末尾的其他内容proxy_pass。NGINX将剥离匹配的前缀/foo,并将剩余的传递给URI的后端服务器/。因此,http://myserver:80/foo/bar将发布到的后端http://localhost:3200/bar

来自proxy_pass上NGINX文档

如果使用URI指定了proxy_pass指令,那么当请求传递到服务器时,与该位置匹配的规范化请求URI的一部分将被该指令中指定的URI代替:


12
为我工作,比我将/添加到位置/ foo / {
Andrei N

这正是我想要的!
anbiniyar

6
这是一个非常干净的解决方案,我希望这是该问题的规范答案。
ralien

2
花了太长时间才意识到保持或消除斜杠的重要性。
帕尔韦兹

5
//xyz如果这样做,它将实际上传递给主机。
Archimedes Trajano

60

绝对最正确的方法和最佳做法通常如下:

location /foo/ {
    proxy_pass http://localhost:3200/; # note the trailing slash!
}

  • 请注意,中的斜杠proxy_pass极为重要,它会自动更改$uri变量,以/foo/使前端的与/后端相对应。无需显式rewrite指令。

  • 此外,注意在尾随/location是非常重要的,以及-没有它,你就有可能在一个点(例如,工作有您的网站看起来怪怪的网址,/fooen/foo/en)。

    此外,尾随/locationproxy_pass也保证了一些特殊的处理,具体根据的文件location指示,以有效地使一个隐含的location = /foo {return 301 /foo/;}为好。

    因此,通过location如上所述定义带有斜杠的a ,不仅可以确保像这样的/fooen无斜杠后缀URL 无效,而且还可以确保/foo不带斜杠的a 也将继续起作用。


参考文档:


看起来像$args丢失了:http://frontend/foo?bar=baz将被代理http://backend/。请注意,args不是url的一部分
Vanuan

@Vanuan,你确定吗?我敢肯定,$args如果您使用上面的代码,仍然应该适当地处理它们,因为它们与分开$uri,并且应该重新组装,除非您在中使用显式变量proxy_pass
cnst

@cnst哦,我知道了。我正在使用主机变量。这与直觉相反。
Vanuan

1
@ArchimedesTrajano,您不正确,因为/foo重定向到时有特殊处理/foo/,因此,除非您在后端做一些奇怪的事情,否则即使/foo请求仍然可以使用上述代码。(BTW实际上已经是答案的一部分。)
cnst

3
尽管此解决方案“似乎”在所有这些论坛上都取得了成功,但应在答案本身中指出Nginx将对URL进行URL解码,并将解码后的URL传递给代理服务器。因此,如果您的URL包含URL编码的部分,则此解决方案将不起作用。
编码

1

尝试

location /foo {
    proxy_pass http://localhost:3200/;
    ....

要么

location ^~ /foo {
    proxy_pass http://localhost:3200/;
    ....

13
如果您给出解释为什么必须像上面这样配置,那么这个答案将是很好的。
masegaloeh,2015年

//xyz如果这样做,它将实际上传递给主机。
Archimedes Trajano

1

@Terabuck对不起,您还没有回复。

您不应该使用localhost,因为您取决于应用程序在具有主机文件的服务器上运行的事实。本地主机只是默认转换为127.0.0.1。没有说明您必须具有此主机文件的文件。拥有一个很常见。

再次具有环回接口是另一个要依靠的常识,但是您仍然依赖于网络堆栈上的环回接口。没有这两种情况很少见。如果您对此担心。至少在unix / linux上,您可以选择套接字。这将消除网络堆栈到达本地主机的需要。请谨慎使用此方法,因为主机操作系统上会考虑一些因素。例如打开文件的数量等。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.