使用 cookie 控制 Nginx 代理目标?

使用 cookie 控制 Nginx 代理目标?

我正在尝试使用有趣的 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}并且我可以看到它可以正常读取内容,但ifs 似乎总是失败。

根据 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_upstreamlocation部分中使用:

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

相关内容