Wyłączanie dekodowania adresów URL w proxy Nginx

21

Gdy przeglądam ten adres URL: http://localhost:8080/foo/%5B-%5Dserver ( nc -l 8080) otrzymuje go takim, jakim jest:

GET /foo/%5B-%5D HTTP/1.1

Jednak gdy proxy tej aplikacji przez proxy nginx (1.1.19):

location /foo {
        proxy_pass    http://localhost:8080/foo;
}

To samo żądanie przekierowane przez port Nginx jest przekazywane z dekodowaną ścieżką:

GET /foo/[-] HTTP/1.1

Zdekodowane nawiasy kwadratowe w ścieżce GET powodują błędy na serwerze docelowym ( HTTP Status 400 - Niedozwolony znak na ścieżce ... ), gdy przybywają bez zmiany znaczenia.

Czy istnieje sposób na wyłączenie dekodowania adresu URL lub jego ponowne zakodowanie, aby serwer docelowy uzyskał dokładnie tę samą ścieżkę, gdy jest kierowany przez nginx? Jakaś sprytna reguła przepisywania adresów URL?

Tomasz Nurkiewicz
źródło
Zgłoszony błąd do nginx: trac.nginx.org/nginx/ticket/262
Tomasz Nurkiewicz

Odpowiedzi:

19

Cytując Valentina V. Barteneva (który powinien uzyskać pełne uznanie za tę odpowiedź):

Cytat z dokumentacji :

  • Jeśli parametr proxy_pass jest podany za pomocą identyfikatora URI , podczas przekazywania żądania do serwera część znormalizowanego identyfikatora URI żądania pasującego do lokalizacji jest zastępowana identyfikatorem URI określonym w dyrektywie

  • Jeśli proxy_passzostanie określony bez identyfikatora URI , identyfikator URI żądania jest przekazywany do serwera w takiej samej formie, w jakiej został wysłany przez klienta podczas przetwarzania oryginalnego żądania

Prawidłowa konfiguracja w twoim przypadku to:

location /foo {
   proxy_pass http://localhost:8080;
}
Tomasz Nurkiewicz
źródło
8
Musiałem się zmienić http://localhost:8080/na http://localhost:8080wypadek, gdyby ktoś miał taką samą sytuację jak ja.
herrtim
4
Dlaczego Nginx dekoduje identyfikator URI przed przekazaniem go do serwera zaplecza? Czy nie miałoby to większego sensu, gdyby nie zmienił URI?
dziobak
@platypus, to utrzymuje się nietknięte, dopóki jawnie rozpocząć wykonywanie podstawienia
CNST
2

Zauważ, że dekodowanie adresów URL, powszechnie znane jako $uri„normalizacja” w dokumentacji nginx, odbywa się przed IFF zaplecza:

  • albo dowolny identyfikator URI jest określony proxy_passsam w sobie, nawet jeśli sam ukośnik jest sam,

  • lub URI jest zmieniany podczas przetwarzania, np rewrite. przez .


Oba warunki są wyraźnie udokumentowane na stronie http://nginx.org/r/proxy_pass (moje podkreślenie):

  • Jeśli proxy_passdyrektywa jest określona za pomocą identyfikatora URI , to po przesłaniu żądania do serwera część znormalizowanego identyfikatora URI żądania pasującego do lokalizacji jest zastępowana identyfikatorem URI określonym w dyrektywie

  • Jeśli proxy_passzostanie określony bez identyfikatora URI , identyfikator URI żądania jest przekazywany do serwera w takiej samej formie , w jakiej jest wysyłany przez klienta podczas przetwarzania pierwotnego żądania, lub przekazywany jest pełny znormalizowany identyfikator URI żądania podczas przetwarzania zmienionego identyfikatora URI


Rozwiązaniem jest albo pominięcie URI, jak w przypadku OP, lub, w istocie, zastosowanie sprytnej rewritereguły:

# map `/foo` to `/foo`:
location /foo {
    proxy_pass  http://localhost:8080;  # no URI -- not even just a slash
}

# map `/foo` to `/bar`:
location /foo {
    rewrite  ^  $request_uri;            # get original URI
    rewrite  ^/foo(/.*)  /bar$1  break;  # drop /foo, put /bar
    return 400;   # if the second rewrite won't match
    proxy_pass    http://localhost:8080$uri;
}

Możesz zobaczyć to na żywo w powiązanej odpowiedzi Przepełnienie stosu , w tym grupie kontrolnej.

cnst
źródło
Dokumentacja jest tutaj myląca. Obie formy zawierają identyfikator URI. Jest to składnik ścieżki, który jest obecny w jednym, a brakuje w drugim.
Michael Hampton
@MichaelHampton, nie zgadzam się - ścieżka jest ogólnie nazywana URI, więc ta bez ścieżki nie zawiera URI.
cnst
Oczywiście sama ścieżka względna może być również prawidłowym adresem URL. Chodzi o to, że reszta to także poprawny identyfikator URI (np http://localhost:8080.). Jeśli się nie zgadzasz, możesz porozmawiać z autorami RFC 3986.
Michael Hampton
@MichaelHampton Niefortunnie wydaje się, że schemat i ścieżka są obowiązkowe, aby być URI, autorytet, argumenty, fragment są opcjonalne
Norman Xu