如何使用Nginx proxy_pass删除路径


77

我在拥有一个正在运行的Web应用程序http://example.com/,并且想在上的单独服务器上“挂载”另一个应用程序http://example.com/en。上游服务器proxy_pass似乎可以运行,但是有一个问题:

upstream luscious {
 server lixxxx.members.linode.com:9001;
}

server {
  root /var/www/example.com/current/public/;
  server_name example.com;

  location /en {
    proxy_pass http://luscious;
  }
}

打开时example.com/en,我的上游应用程序返回404 not found /en。这是有道理的,因为上游没有路径/en

proxy_path正确的解决方案?我应该重写“上游”,以便它/en代替它作为根路径吗?还是有一条指令允许我重写传递到上游的路径?

Answers:


133

这可能是执行所需操作的最有效方法,而无需使用任何正则表达式:

location = /en {
    return 302 /en/;
}
location /en/ {
    proxy_pass http://luscious/;  # note the trailing slash here, it matters!
}

1
据我所知,最后一部分仍将“ / en”作为路径传递给代理,不是吗?
berkes 2013年

15
@berkes,不,这不会-斜线proxy_pass是有区别的。此外,此答案比您想出的答案更正确,因为它还确保将其proxy_redirect停留在default,因此,您仍然可以302在后端使用et al,并使其在任何地方都能正常工作。
cnst 2013年

4
啊,我错过了结尾的斜线:(
Vanuan

3
啊!拖尾!
巴里马克'17

4
经过3个小时的搜索,是的。。。是斜线。谢了哥们!
Lucas P.

12

我想解决一个越来越流行的基于正则表达式的新答案。

location ~ ^/en(/?)(.*)$ {  # OOPS!
  proxy_pass http://luscious/$2$is_args$args;  # OOPS!
}

乍看起来,该解决方案看起来更可爱,但是由于多种原因,它是错误的。

  • 上面的正则表达式将匹配请求uri /enjoy,将其重定向到/joy上游。这是真的吗?

  • 请求/en不会导致任何重定向,直接/从上游提供服务(几乎就像发出了请求一样/en/,但不完全一样)。如果您在上游的根页面中使用相对URI(否则,为什么/en/在上游URI中没有前缀呢?)(例如src="style.css"(它可能引用特定url("menu.png")于语言的语言)),那么浏览器将请求作为/style.css代替/en/style.css。(或者,即使您到处都使用绝对URI,如果有人相对地引用了一个晦涩的半可选资源,该怎么办?)糟糕,该站点可能突然不起作用,但仅在某些情况下或在某些情况下才起作用。

  • 根据我先前对OP自己的答案已经提到的另一个问题的建议,使用正则表达式可防止该proxy_redirect指令具有默认值defaultoff而是改为使用默认值。这意味着,如果上游Location: http://127.0.0.1:8080/en/dir/在请求时回复/en/dir,那么客户端将看到该内容,这显然将无法正常工作。(对于/en首先提示正则表达式使用的请求,这尤其具有讽刺意味,但是该特定实现却遇到了如上所述的另一个问题。)另外,如果您已经在使用upstream指令,那么,如果您尝试使用自定义服务器,则可能会变得更加丑陋,尤其是如果您可能有多个上游服务器时-您如何proxy_redirect为每个服务器单独设置一个?您也可以在其中使用正则表达式proxy_redirect,甚至可以匹配任何主机,但是如果将来您决定进行跨域重定向该怎么办?

为了尝试使用单个基于正则表达式的位置来解决上述问题,我们可以执行以下操作(请注意,为了使操作更简单,proxy_pass我们还必须从upstream基于-的指令中删除对服务器的引用proxy_redirect):

location ~ ^/en/?((?<=/).*)?$ {
  location = /en { return 302 /en/; }
  proxy_pass http://127.0.0.1:8080/$1$is_args$args;
  proxy_redirect http://127.0.0.1:8080/ /en/;
}

因此,如果您问我,与两个同级顶级位置相对应的原始解决方案仍然比通过使用正则表达式路线而陷入一个兔子洞更好。


这将导致异常:nginx: [emerg] location "/en" is outside location "^/en/?((?<=/).*
Athlan '16

1
@Athlan,那是因为您首先不应该真正使用它!如果仍然愿意,可以将该位置放在正则表达式之外。
cnst

将本地化= / en放在外面工作真的很好!谢谢
塞巴斯蒂安·韦伯

7

因此,我在stackoverflow上找到了答案

upstream luscious {
 server lixxxx.members.linode.com:9001;
}

server {
  root /var/www/example.com/current/public/;
  server_name example.com;

  location ~ ^/en(/?)(.*) {
    proxy_pass http://luscious/$2;
  }
}

基本上:将正则表达式传递到位置,并将backref传递给proxy_pass URL。


我认为“ proxy_pass luscious / $ ;” 应该是“ proxy_pass luscious / $ 2
Zafer

1
@Zafer是正确的,以上答案给了我一个错误
franck

我已经更改了答案,但是手边没有可尝试使用的服务器ATM,因此未经过验证。
berkes '18 -10-2

0

会计Nginx文件

为了将请求传递到HTTP代理服务器,必须在一个位置内指定proxy_pass指令。例如:

location /some/path/ {
    proxy_pass http://www.example.com/link/;
}

此示例配置导致将在此位置处理的所有请求传递到指定地址的代理服务器。该地址可以指定为域名或IP地址。该地址可能还包含端口:

location ~ \.php {
    proxy_pass http://127.0.0.1:8000;
}

请注意,在上面的第一个示例中,代理服务器的地址后跟一个URI / link /。如果URI和地址一起指定,它将替换请求URI中与location参数匹配的部分。例如,此处带有/some/path/page.html URI的请求将被代理到http://www.example.com/link/page.html。如果指定的地址没有URI,或者无法确定URI的要替换的部分,则将传递完整的请求URI(可能已修改)。

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.