NGINX: rewrite kontra return

08 Jan 2018

best-practices  http  nginx  return  rewrite 

Share on:

Protokół HTTP pozwala serwerom przekierować żądanie klienta do innej lokalizacji. Jest to przydatne podczas przenoszenia zawartości pod nowy adres URL, usuwania stron lub zmiany nazw domen, lub łączenia stron internetowych.

Przekierowanie adresu URL odbywa się z różnych powodów:

Zasadniczo istnieją dwa sposoby implementacji przekierowań w NGINX: za pomocą dyrektywy przepisywania (rewrite) oraz zwracania (return).

Te dyrektywy (pochodzące z modułu ngx_http_rewrite_module) są bardzo przydatne, jednak o czym chcę wspomnieć już na samym wstępie (zgodnie z dokumentacją NGINX), jedynie w 100% bezpieczne rzeczy, które można wykonać za ich pomocą, to:

Co ważne, chodzi o wykorzystanie ich w kontekście location. Wszystko inne może spowodować nieprzewidziane zachowanie, w tym potencjalny segmentation fault (SIGSEGV).

Reguły przepisywania zmieniają część lub całość adresu URL w żądaniu klienta, zwykle w jednym z dwóch celów:

Dyrektywa rewrite #

Dyrektywa rewrite jest przetwarzana sekwencyjnie w kolejności pojawienia się w pliku konfiguracyjnym. Jest wolniejsza (ale nadal niezwykle szybka) niż dyrektywa return i zwraca odpowiedź z kodem 302 we wszystkich przypadkach, z wyjątkiem ustawienia parametru permanent.

Musisz wiedzieć, że dyrektywa rewrite zwraca tylko kod 301 lub 302.

Dyrektywa przepisywania po prostu zmienia identyfikator URI żądania, a nie odpowiedź na żądanie. Co ważne, przepisywana jest tylko część oryginalnego adresu URL, która pasuje do wyrażenia regularnego. Można go użyć do tymczasowych zmian adresu URL.

Czasami używam dyrektywy przepisywania, aby przechwytywać elementy w oryginalnym adresie URL, zmieniać lub dodawać elementy na ścieżce i ogólnie, gdy robię coś bardziej złożonego:

location / {

  ...

  rewrite ^/users/(.*)$ /user.php?username=$1 last;

  # lub:
  rewrite ^/users/(.*)/items$ /user.php?username=$1&page=items last;

}

Dyrektywa ta akceptuje poniższe parametry:

Ważna uwaga:

Sam widzisz, że jest to trochę pogmatwane i łatwo popełnić błąd. Dlatego, abyś lepiej zrozumiał działanie obu dyrektyw, spójrz na różnicę między flagami last i break podczas akcji:

Dyrektywa last:

Dyrektywa break:

Jeżeli nadal nie jest to jasne, polecam następujące wyjaśnienia:

Dyrektywa return #

Drugą dyrektywą odpowiedzialną za przekierowania jest dyrektywa return. Jest ona szybszy niż rewrite, ponieważ nie zajmuje się analizą wyrażenia regularnego, które wymagałoby oceny. Przerywa przetwarzanie i zwraca HTTP 301 (domyślnie) do klienta. Dzięki temu NGINX odpowiada bezpośrednio na żądanie, a cały adres URL jest przekierowywany na podany adres URL.

Dyrektywa powrotu/zwracania przydaje się w następujących przypadkach:

server {

  ...

  return 301 https://example.com$request_uri;

}
server {

  ...

  # Jest to tylko przykład. Nigdy nie powinieneś używać 'if' jak poniżej:
  if ($host = www.example.com) {

    return 301 https://example.com$request_uri;

  }

}
server {

  ...

  return 444;

}
server {

  ...

  if ($request_method = POST) {

    return 405;

  }

  # lub:
  if ($invalid_referer) {

    return 403;

  }

  # lub:
  if ($request_uri ~ "^/app/(.+)$") {

    return 403;

  }

  # lub:
  location ~ ^/(data|storage) {

    return 403;

  }

}
server {

  ...

  # NGINX nie zezwala na odpowiedź z kodem 200 bez podania treści:
  # - 200 musi być z zasobem w odpowiedzi.
  # - '204 No Content' oznacza, że „zrealizowałem żądanie, ale nie ma treści do zwrócenia”
  return 204;
  # Lub możesz podać ładunek do zwrócenia klientowi:
  return 204 "it's all okay";

  # Ponieważ domyślnym typem treści jest application/octet-stream, przeglądarka zaoferuje
  # „zapisanie pliku”. Jeśli chcesz zobaczyć odpowiedź w przeglądarce, dodaj poprawny
  # Content-Type, tj.:
  # add_header Content-Type text/plain;

}

Do ostatniego przykładu: bądź ostrożny, jeśli używasz takiej konfiguracji do sprawdzenia stanu aplikacji (ang. health check). Podczas gdy kod HTTP 204 jest semantycznie idealny do kontroli statusu usługi (wskazanie poprawności bez zawartości), niektóre usługi nie uważają go za poprawny.