Como os parâmetros de string de consulta podem ser encaminhados por meio de proxy_pass com nginx?

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

O snippet acima redirecionará as solicitações em que o url inclui a string "serviço" para outro servidor, mas não inclui os parâmetros de consulta.

Alex Luya
fonte

Respostas:

163

Da documentação do proxy_pass :

Um caso especial é o uso de variáveis ​​na instrução proxy_pass: O URL solicitado não é usado e você é totalmente responsável por construir o URL de destino sozinho.

Como você está usando $ 1 no destino, o nginx depende de você para dizer exatamente o que deve ser passado. Você pode consertar isso de duas maneiras. Primeiro, remover o início do uri com um proxy_pass é trivial:

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

Ou se você quiser usar o local do regex, apenas inclua os argumentos:

location ~* ^/service/(.*) {
  proxy_pass http://apache/$1$is_args$args;
}
Kolbyjack
fonte
1
Não acredito que você possa fazer o último. Eu tentei e nginx reclamou para mim.
duma
3
Reclamou como? Acabei de testá-lo no nginx 1.3.4 e funcionou bem para mim.
kolbyjack
Humm .. Não consigo me lembrar agora :( Mas acho que pode estar relacionado ao "~ *". No entanto, acabei de verificar e tenho o nginx 1.2.3 (através do homebrew). Talvez seja isso?
duma
"proxy_redirect default" não pode ser usado com a diretiva "proxy_pass" com variáveis
Jean-Philippe Caruana
1
tem que usar reescrever location /service/ { rewrite ^\/service\/(.*) /$1 break; proxy_pass http://apache; }
Andrew Arnautov
27

Eu uso uma versão ligeiramente modificada da segunda abordagem de Kolbyjack com em ~vez de~* .

location ~ ^/service/ {
  proxy_pass http://apache/$uri$is_args$args;
}
Sebastian vom Meer
fonte
10

Eu modifiquei o código @kolbyjack para fazê-lo funcionar para

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

com parâmetros

location ~ ^/service/?(.*) {
    return 301 http://service_url/$1$is_args$args;
}
Pranav Garg
fonte
1
Lembre-se de que isso fará com que o servidor retorne uma resposta 301 ao cliente antes de redirecionar. A proxy_passdiretiva acima faz o redirecionamento no lado do servidor.
Luke Peterson
1
Isso será interrompido se seus parâmetros de consulta contiverem caracteres codificados em URL (%). Em vez disso, use a resposta de Andrew.
David Weber
9

você tem que usar reescrever para passar parâmetros usando proxy_pass aqui está o exemplo que fiz para a implantação do aplicativo angularjs para s3

S3 Static Website Hosting Rota todos os caminhos para index.html

adotado para suas necessidades seria algo como

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

se você quiser terminar em http://127.0.0.1:8080/query/params/

se você quiser terminar em http://127.0.0.1:8080/service/query/params/, você precisará de algo como

location /service/ {
    rewrite ^\/(.*) /$1 break;
    proxy_pass http://apache;
}
Andrew Arnautov
fonte
1
Parece que lida bem com path params ( /path/params), mas não consulta params ( ?query=params)?
Will
Ah não, erro meu, os parâmetros de consulta devem ser adicionados automaticamente (eles estão em meus testes).
Será
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
fonte
1

Para redirecionar sem string de consulta, adicione as linhas abaixo no bloco do servidor na linha da porta de escuta:

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

Com Query String:

if ($uri ~ .*.containingString$) {
           return 301 https://$host/$uri/?$query_string;
}
Abhishek
fonte
1
A documentação do nginx é explícita para evitar o uso ifquando possível. Nesse caso, a solução pode ser acertada usando locationcomo mostrado em outras respostas.
Andrés Morales
2
enfim, mais uma solução, mesmo que tenha desvantagens, é melhor
Dmitry Malugin