使用Cookie控制Nginx代理目标?


11

我正在尝试使用有趣的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块已激活,但是与其代理请求(如我认为的那样),它返回的是指向指定URL的302重定向-这不是我要执行的操作:我需要服务器透明地将请求中继到后端,并将响应通过管道传递到原始客户端。

我究竟做错了什么?

Answers:


16

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

基本上,您定义一个mapin http部分

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

然后,您只需$my_upstreamlocation(s)部分中使用:

location /original-request {
  proxy_pass http://$my_upstream$uri;
}

Nginx懒惰地评估映射变量,一次(每个请求)以及您使用它们时。


3
谢谢,这是比我更好的方法,最值得注意的是,因为我可以直接使用命名的cookie变量(不确定为什么不能使用if)并实现了它。不过有一个问题-Nginx(至少我的版本为1.0.0)不喜欢中的编号捕获map,因此我不得不使用它~^(?P<name>[\w-]+) $name;。我已经相应地编辑了您的答案。
摊铺

3

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

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覆盖。


0

您尝试过$ http_cookie吗?http://wiki.nginx.org/HttpRewriteModule

如果($ http_cookie〜*“ proxy-target-A”){foo; }


尽管确实不确定为什么我不能只针对特定的cookie名称进行测试,但这确实可以用于测试。我不喜欢的是rewrite实际上并没有进行代理重写,而是将重定向返回给客户端,并且我不能在该if块中使用proxy_pass 。我已经相应地更新了问题。
古斯

0

我有一些示例,用于根据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;
    }

您正在使用哪个版本的Nginx?我正在使用1.0,并且当我使用您在此处指定的proxy_pass时,收到以下错误消息:nginx: [emerg] "proxy_pass" may not have URI part in location given by regular expression, or inside named location, or inside the "if" statement, or inside the "limit_except" block in /etc/nginx/conf.d/proxy.conf:47
Guss,

我使用nginx-0.8.53-1.el5
chocripple


论坛中的解决方案是在代理到另一台服务器时不更改请求URI,但这正是我需要做的-重写请求URI以将目标URL定位为不同于原始URL所包含的应用程序。另外,您的示例似乎也在proxy_pass命令中使用了请求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.