Controlando o alvo do proxy Nginx usando um cookie?

9

Estou tentando converter um proxy reverso usando uma configuração interessante do mod_rewrite do Apache para usar o Nginx (devido a preocupações externas que estamos passando do Apache para o Nginx, e a maioria das coisas funciona bem, exceto essa parte).

Minha configuração original era ler um cookie HTTP (definido por algum aplicativo) e, dependendo do seu valor, direcionar o proxy reverso para diferentes backends. Foi algo assim:

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]

Estou tentando conseguir o mesmo usando o Nginx, e minha configuração inicial era algo assim (onde "proxy_override" é o nome do 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;
}

Mas isso não aconteceu. Eu tentei ver se o Nginx pode ler meu cookie escrevendo o proxy principal para redirecionar para algo baseado em ${cookie_proxy_override} e posso ver que ele lê o conteúdo, mas o if s parece sempre falhar.

Minha próxima tentativa, de acordo com a resposta de Rikih, foi esta:

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

E agora eu posso ver que o bloco if é ativado, mas em vez de fazer proxy na solicitação (como achei que faria) ele retorna um redirecionado 302 para a URL especificada - o que não é o que estou tentando Eu preciso que o servidor transmita a solicitação de forma transparente para os backends e canalize a resposta para o cliente original.

O que estou fazendo de errado?

    
por Guss 11.05.2011 / 17:23

4 respostas

14

Semelhante a esta resposta . A abordagem idiomática do Nginx para esse tipo de problema é via map .

Basicamente, você define uma map em http seção

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

Você simplesmente usa $my_upstream em location seção (s):

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

O Nginx avalia as variáveis do mapa preguiçosamente, apenas uma vez (por solicitação) e quando você as usa.

    
por 21.08.2011 / 21:48
2

Eventualmente, minha solução se resume a isso:

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

O teste é feito no escopo server para cada solicitação (antes que o redirecionamento real seja resolvido) e é usado apenas para definir uma variável - aparentemente, esse é um uso suportado do módulo "reescrever" do Nginx. Ele também testa o $http_cookie inteiro como o @Rikih sugeriu, mas inclui o nome do cookie para garantir que eu não corresponda a coisas aleatórias que as pessoas possam estar jogando em mim.

Em seguida, no escopo location em que desejo redirecionar, uso o nome da variável que contém a configuração de envio de dados padrão ou foi substituído pelo cookie.

    
por 21.08.2011 / 18:54
0

você tentou $ http_cookie? link

if ($ http_cookie ~ * "proxy-alvo-A") {   foo; }

    
por 12.05.2011 / 10:07
0

Eu tenho uma amostra que eu uso para detectar o cabeçalho da solicitação com base no udid e está funcionando, pode ser que você tenha uma ideia.

   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;
    }
    
por 12.05.2011 / 15:46