使用 cookie 控制 Nginx 代理目标?

Gus*_*uss 14 mod-rewrite nginx reverse-proxy cookie

我正在尝试使用有趣的 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]
Run Code Online (Sandbox Code Playgroud)

我正在尝试使用 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;
}
Run Code Online (Sandbox Code Playgroud)

但它没有。我试图通过编写主代理重定向到基于${cookie_proxy_override}的内容来查看 Nginx 是否可以读取我的 cookie ,我可以看到它读取的内容很好,但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;
}
Run Code Online (Sandbox Code Playgroud)

现在我可以看到if块被激活了,但是它没有代理请求(就像我认为的那样)它返回一个 302 重定向到指定的 URL - 这不是我想要做的:我需要服务器透明地将请求中继到后端并将响应通过管道传输到原始客户端。

我究竟做错了什么?

Ale*_*rov 20

类似于这个答案。Nginx 解决此类问题的惯用方法是通过map.

基本上,您定义一个mapinhttp部分

map $cookie_proxy_override $my_upstream {
  default default-server-or-upstream;
  ~^(?P<name>[\w-]+) $name;
}
Run Code Online (Sandbox Code Playgroud)

然后您只需$my_upstreamlocation部分中使用:

location /original-request {
  proxy_pass http://$my_upstream$uri;
}
Run Code Online (Sandbox Code Playgroud)

Nginx 懒惰地评估地图变量,仅在您使用它们时(每个请求)一次。

  • 谢谢,这是比我更好的方法,最值得注意的是因为我可以直接使用命名的 cookie 变量(不知道为什么我不能在 `if` 中)并且我实现了它。但是有一个问题 - Nginx(至少我的版本:1.0.0)不喜欢`map`中的编号捕获,所以我不得不使用`~^(?P&lt;name&gt;[\w-]+) $name ;` 代替。我已经相应地编辑了您的答案。 (3认同)

Gus*_*uss 5

最终我的解决方案归结为:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

测试在server每个请求的范围内完成(在实际重定向被解析之前)并且仅用于设置变量 - 这显然是 Nginx“重写”模块的支持用法。它还$http_cookie像@Rikih 建议的那样测试整个内容,但包括 cookie 的名称,以确保我不匹配人们可能扔给我的随机内容。

然后在location我想要进行重定向的范围内,我使用包含默认上游配置或被 cookie 覆盖的变量名称。