Контроль цілі проксі Nginx за допомогою файлу cookie?


11

Я намагаюся перетворити зворотний проксі, використовуючи цікавий параметр mod_rewrite Apache, щоб використовувати замість нього Nginx (через зовнішні проблеми ми переходимо від Apache до Nginx, і більшість все працює нормально, крім цієї частини).

Моя оригінальна настройка полягала в тому, щоб прочитати файл cookie HTTP (встановлений якоюсь програмою) і, залежно від його значення, направити зворотний проксі-сервер на різні програми. Вийшло приблизно так:

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, здається, завжди не виходить .

Наступна моя спроба, згідно з відповіддю Рікіка, була така:

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 - що не те, що я намагаюся зробити: мені потрібен сервер прозоро ретранслювати запит на вихідні дані та передавати відповідь вихідному клієнту.

Що я роблю неправильно?

Відповіді:


16

Схожа на цю відповідь . Ідіоматичний підхід 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 ліниво оцінює змінні карти лише один раз (за запит) і коли ви їх використовуєте.


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

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


Це справді спрацювало для тесту, хоча я не впевнений, чому я не можу просто перевірити конкретне ім’я файлу cookie. Що мені не сподобалося, це те, rewriteщо насправді не перезаписується проксі, але натомість повертає переадресацію клієнту, і я не можу використовувати proxy_pass в ifблоці. Я відповідно оновив питання.
Гасс

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

можливо, ви хочете подивитися форум.nginx.org
read.php?

Рішення на форумі полягає в тому, щоб не змінювати URI запиту при зверненні до іншого сервера, але саме це мені потрібно зробити - переписати URI запиту, щоб націлити його на додаток, відмінний від оригінальної URL-адреси. Крім того, ваш приклад також використовує URI запиту в proxy_passкоманді, тому я не впевнений, як це може працювати для вас з огляду на вищезгадане обговорення на форумі.
Гасс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.