Як параметри рядка запиту можна пересилати через proxy_pass з nginx?


114
upstream apache {
   server 127.0.0.1:8080;
}
server{
   location ~* ^/service/(.*)$ {
      proxy_pass http://apache/$1;
      proxy_redirect off;
   }
 }

Вищенаведений фрагмент буде перенаправляти запити, де URL включає рядок "послуга" на інший сервер, але він не включає параметри запиту.

Відповіді:


163

З документації про proxy_pass :

Особливий випадок - використання змінних у операторі proxy_pass: Запрошена URL-адреса не використовується, і ви несете повну відповідальність за самостійне створення цільової URL-адреси.

Оскільки ви використовуєте $ 1 у цілі, nginx покладається на вас, щоб сказати йому, що саме потрібно пройти. Виправити це можна двома способами. По-перше, зачистка початку uri за допомогою proxy_pass тривіальна:

location /service/ {
  # Note the trailing slash on the proxy_pass.
  # It tells nginx to replace /service/ with / when passing the request.
  proxy_pass http://apache/;
}

Або якщо ви хочете скористатися місцем регулярного виразу, просто додайте аргументи:

location ~* ^/service/(.*) {
  proxy_pass http://apache/$1$is_args$args;
}

1
Я не вірю, що ти можеш зробити останнє. Я спробував, і nginx на мене поскаржився.
дума

3
Поскаржився як? Я щойно тестував його на nginx 1.3.4, і він добре працював для мене.
колб'як

Гумм .. Не можу зараз згадати :( Але я відчуваю, що це могло бути пов’язано з "~ *". Однак я просто перевірив, і у мене є nginx 1.2.3 (через домашню мову). Можливо, це все?
думи

"proxy_redirect default" не можна використовувати з директивою "proxy_pass" зі змінними
Жан-Філіпп Каруана

1
доведеться користуватися переписати location /service/ { rewrite ^\/service\/(.*) /$1 break; proxy_pass http://apache; }
Андрій Арнаутов

27

Я використовую трохи модифіковану версію другого підходу kolbyjack, ~а не ~*.

location ~ ^/service/ {
  proxy_pass http://apache/$uri$is_args$args;
}

10

Я змінив код @kolbyjack, щоб він працював

http://website1/service
http://website1/service/

з параметрами

location ~ ^/service/?(.*) {
    return 301 http://service_url/$1$is_args$args;
}

1
Майте на увазі, це змусить сервер повернути клієнту відповідь 301 перед перенаправленням. Наведена proxy_passвище директива робить перенаправлення на стороні сервера.
Люк Петерсон

1
Це порушиться, якщо ваші параметри запиту містять закодовані символи URL (%). Використовуйте натомість відповідь Андрія.
Девід Вебер

9

вам потрібно використовувати переписати, щоб передавати парами за допомогою proxy_pass, ось приклад, який я зробив для розгортання програми angularjs до s3

Статичний хостинг веб-сайтів S3 прокладе всі шляхи до Index.html

прийняте до ваших потреб було б щось подібне

location /service/ {
    rewrite ^\/service\/(.*) /$1 break;
    proxy_pass http://apache;
}

якщо ви хочете опинитися в http://127.0.0.1:8080/query/params/

якщо ви хочете опинитися в http://127.0.0.1:8080/service/query/params/, вам знадобиться щось на зразок

location /service/ {
    rewrite ^\/(.*) /$1 break;
    proxy_pass http://apache;
}

1
Це виглядає так, що він обробляє парами шляху ( /path/params) добре, але не запитує парами ( ?query=params)?
Чи буде

Ах ні, моя помилка, параметри запитів слід додавати автоматично (вони є в моєму тестуванні).
Чи буде

2

github gist https://gist.github.com/anjia0532/da4a17f848468de5a374c860b17607e7

#set $token "?"; # deprecated

set $token ""; # declar token is ""(empty str) for original request without args,because $is_args concat any var will be `?`

if ($is_args) { # if the request has args update token to "&"
    set $token "&";
}

location /test {
    set $args "${args}${token}k1=v1&k2=v2"; # update original append custom params with $token
    # if no args $is_args is empty str,else it's "?"
    # http is scheme
    # service is upstream server
    #proxy_pass http://service/$uri$is_args$args; # deprecated remove `/`
    proxy_pass http://service$uri$is_args$args; # proxy pass
}

#http://localhost/test?foo=bar ==> http://service/test?foo=bar&k1=v1&k2=v2

#http://localhost/test/ ==> http://service/test?k1=v1&k2=v2

1

Для переадресації без рядка запиту додайте нижче рядки в блоці сервера під лінією порту прослуховування:

if ($uri ~ .*.containingString$) {
           return 301 https://$host/$uri/;
}

З рядком запиту:

if ($uri ~ .*.containingString$) {
           return 301 https://$host/$uri/?$query_string;
}

1
Документація nginx явна, щоб уникнути використання, ifколи можливо. У цьому випадку рішення може бути правильним, використовуючи, locationяк показано в інших відповідях.
Андрес Моралес

2
все одно ще одне рішення, навіть якщо воно має недоліки, краще
Дмитро Малугін

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.