Как можно передать параметры строки запроса через proxy_pass с помощью nginx?

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

Приведенный выше фрагмент будет перенаправлять запросы, URL-адрес которых включает строку «service», на другой сервер, но не включает параметры запроса.

Алекс Луя
источник

Ответы:

164

Из документации 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 пожаловался мне.
duma
3
Жаловались как? Я только что протестировал его на nginx 1.3.4, и у меня он работал нормально.
kolbyjack
Хмм .. Я не могу вспомнить сейчас :( Но мне кажется, что это могло быть связано с "~ *". Однако я только что проверил, и у меня есть nginx 1.2.3 (через homebrew). Может быть, это все?
duma
«proxy_redirect default» нельзя использовать с директивой «proxy_pass» с переменными
Жан-Филипп Каруана
1
придется использовать rewrite 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

вам нужно использовать rewrite для передачи параметров с помощью 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)?
Will
Ах нет, моя ошибка, параметры запроса должны добавляться автоматически (они в моем тестировании).
Will
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
AnJia
источник
1

Для перенаправления без строки запроса добавьте следующие строки в блоке сервера под строкой порта прослушивания:

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

Со строкой запроса:

if ($uri ~ .*.containingString$) {
           return 301 https://$host/$uri/?$query_string;
}
Абхишек
источник
1
Документация nginx явно не используется, ifкогда это возможно. В этом случае решение может быть правильным, locationкак показано в других ответах.
Андрес Моралес
2
в любом случае еще одно решение, даже если оно имеет недостатки, лучше
Дмитрий Малугин