W jaki sposób parametry ciągu zapytania mogą być przekazywane przez proxy_pass z nginx?

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

Powyższy fragment kodu przekierowuje żądania, których adres URL zawiera ciąg „service”, na inny serwer, ale nie zawiera parametrów zapytania.

Alex Luya
źródło

Odpowiedzi:

163

Z dokumentacji proxy_pass :

Specjalnym przypadkiem jest użycie zmiennych w instrukcji proxy_pass: żądany adres URL nie jest używany i jesteś w pełni odpowiedzialny za samodzielne skonstruowanie docelowego adresu URL.

Ponieważ używasz 1 $ w celu, nginx polega na tobie, aby powiedzieć mu dokładnie, co ma przekazać. Możesz to naprawić na dwa sposoby. Po pierwsze, usunięcie początku uri za pomocą proxy_pass jest trywialne:

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

Lub jeśli chcesz użyć lokalizacji wyrażenia regularnego, po prostu dołącz argumenty:

location ~* ^/service/(.*) {
  proxy_pass http://apache/$1$is_args$args;
}
kolbyjack
źródło
1
Nie wierzę, że możesz zrobić to drugie. Próbowałem i Nginx poskarżył się do mnie.
duma
3
Jak skarżył się? Właśnie przetestowałem go na nginx 1.3.4 i działało dobrze.
kolbyjack
Humm .. Nie mogę sobie teraz przypomnieć :( Ale wydaje mi się, że mogło to być związane z "~ *". Jednak właśnie sprawdziłem i mam nginx 1.2.3 (przez homebrew). Może to wszystko?
duma
„proxy_redirect default” nie może być używane z dyrektywą „proxy_pass” ze zmiennymi
Jean-Philippe Caruana,
1
trzeba użyć przepisywania location /service/ { rewrite ^\/service\/(.*) /$1 break; proxy_pass http://apache; }
Andrew Arnautov
27

Używam nieco zmodyfikowanej wersji drugiego podejścia Kolbyjacka z ~zamiast ~*.

location ~ ^/service/ {
  proxy_pass http://apache/$uri$is_args$args;
}
Sebastian vom Meer
źródło
10

Zmodyfikowałem kod @kolbyjack, aby działał

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

z parametrami

location ~ ^/service/?(.*) {
    return 301 http://service_url/$1$is_args$args;
}
Pranav Garg
źródło
1
Należy pamiętać, że spowoduje to, że serwer zwróci klientowi odpowiedź 301 przed przekierowaniem. Powyższa proxy_passdyrektywa wykonuje przekierowanie po stronie serwera.
Luke Peterson,
1
Spowoduje to uszkodzenie, jeśli parametry zapytania zawierają zakodowane znaki adresu URL (%). Zamiast tego użyj odpowiedzi Andrzeja.
David Weber
9

musisz użyć rewrite, aby przekazać parametry za pomocą proxy_pass, tutaj jest przykład, który zrobiłem dla wdrożenia aplikacji angularjs do s3

S3 Statyczny hosting witryny sieci Web kieruje wszystkie ścieżki do pliku Index.html

dostosowane do twoich potrzeb byłoby coś takiego

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

jeśli chcesz skończyć w http://127.0.0.1:8080/query/params/

jeśli chcesz skończyć w http://127.0.0.1:8080/service/query/params/ , potrzebujesz czegoś takiego

location /service/ {
    rewrite ^\/(.*) /$1 break;
    proxy_pass http://apache;
}
Andrew Arnautov
źródło
1
Wygląda na to, że dobrze obsługuje parametry ścieżki ( /path/params), ale nie params zapytania ( ?query=params)?
Will
Ach nie, mój błąd, parametry zapytania powinny być dodawane automatycznie (są w moich testach).
Będzie
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
źródło
1

Aby przekierować bez ciągu zapytania, dodaj poniższe wiersze w bloku serwera pod linią portu nasłuchiwania:

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

Z ciągiem zapytania:

if ($uri ~ .*.containingString$) {
           return 301 https://$host/$uri/?$query_string;
}
Abhishek
źródło
1
Dokumentacja nginx jest jawna, aby unikać jej używania, ifgdy jest to możliwe. W takim przypadku rozwiązanie może być prawidłowe, locationjak pokazano w innych odpowiedziach.
Andrés Morales
2
zresztą jeszcze jedno rozwiązanie, nawet jeśli ma wady, jest lepsze
Dmitry Malugin