我正在尝试使用有趣的 Apache mod_rewrite 设置转换反向代理以使用 Nginx(由于外部问题,我们正在从 Apache 迁移到 Nginx,并且除了这部分之外,大多数一切都运行良好)。
我最初的设置是读取 HTTP cookie(由某个应用程序设置),并根据其值将反向代理定向到不同的后端。它大致如下:
RewriteCond %{HTTP_COOKIE} proxy-target-A
RewriteRule ^/original-request/ http://backend-a/some-application [P,QSA]
RewriteCond %{HTTP_COOKIE} proxy-target-B
RewriteRule ^/original-request http://backend-b/another-application [P,QSA]
RewriteRule ^/original-request http://primary-backend/original-application [P,QSA]
我正在尝试使用 Nginx 实现相同的功能,我的初始配置如下(其中“proxy_override”是 cookie 的名称):
location /original-request {
if ($cookie_proxy_override = "proxy-target-A") {
rewrite . http://backend-a/some-application;
break;
}
if ($cookie_proxy_override = "proxy-target-B") {
rewrite . http://backend-b/another-application;
break;
}
proxy_pass http://primary-backend/original-application;
}
但事实并非如此。我尝试通过编写主代理来重定向到基于的内容来查看 Nginx 是否能够读取我的 cookie,${cookie_proxy_override}
并且我可以看到它可以正常读取内容,但if
s 似乎总是失败。
根据 Rikih 的回答,我的下一次尝试是这样的:
location /original-request {
if ($http_cookie ~ "proxy-target-A") {
rewrite . http://backend-a/some-application;
break;
}
if ($http_cookie ~ "proxy-target-B") {
rewrite . http://backend-b/another-application;
break;
}
proxy_pass http://primary-backend/original-application;
}
现在我可以看到if
块已被激活,但它没有代理请求(就像我认为的那样),而是返回一个 302 重定向到指定的 URL - 这不是我想要做的:我需要服务器透明地将请求中继到后端并将响应传送给原始客户端。
我究竟做错了什么?
答案1
如同这个答案. Nginx 解决此类问题的惯用方法是通过map
。
map
基本上,你在http
部分中定义一个
map $cookie_proxy_override $my_upstream {
default default-server-or-upstream;
~^(?P<name>[\w-]+) $name;
}
然后您只需$my_upstream
在location
部分中使用:
location /original-request {
proxy_pass http://$my_upstream$uri;
}
Nginx 以惰性方式评估映射变量,仅评估一次(每个请求)并且仅在您使用它们时进行。
答案2
最终我的解决方案归结为:
server {
...
set $upstream "default-server-or-upstream";
if ($http_cookie ~ "proxy_override=([\w-]+)") {
set $upstream $1;
}
location /original-request {
proxy_pass http://$upstream/original-application
}
}
测试在server
每个请求的范围内完成(在实际重定向解析之前),仅用于设置变量 - 这显然是 Nginx“重写”模块支持的用法。它还会$http_cookie
像 @Rikih 建议的那样测试整个内容,但包括 cookie 的名称,以确保我不会匹配人们可能向我抛出的随机内容。
然后在location
我想要执行重定向的范围内,我使用包含默认上游配置或被 cookie 覆盖的变量名。
答案3
您尝试过 $http_cookie 吗?http://wiki.nginx.org/HttpRewriteModule
如果 ($http_cookie ~* "proxy-target-A" ) { foo; }
答案4
我有一个用于根据 udid 检测请求标头的示例,它正在运行,也许您会对此有所了解。
location / {
proxy_set_header Host $http_host;
if ($request_uri ~ ^/(.*)udid=xxxxxxxxxxxxxx(.*)$) {
proxy_pass http://1.1.1.1$request_uri;
break;
}
if ($request_uri ~ ^/(.*)udid=yyyyyyyyyyyyyy(.*)$) {
proxy_pass http://3.3.3.3$request_uri;
break;
}
proxy_pass http://2.2.2.2$request_uri;
}