🤖🚫 AI-free content. This post is 100% written by a human, as is everything on my blog. Enjoy!

Директива try_files в Nginx как замена mod_rewrite

March 29, 2012 in Software

Подход к настройкам у Apache и у nginx настолько разный, что, настраивая последний по привычке, обычно делаешь все слишком сложно.

Если ты когда-нибудь настраивал Apache, то, скорее всего, имел дело с mod_rewrite. Очень часто mod_rewrite используется для того, чтобы выполнить какое-то действие в случае, когда у сервера запрошен не файл:

ЕСЛИ запрошенный адрес соответствует файлу
ТО вернуть клиенту этот файл
ИНАЧЕ вызвать скрипт для обработки запроса

или, как вариант

ЕСЛИ запрошенный адрес сохранен в кеш
ТО вернуть результат из кеша
ИНАЧЕ запросить результат у скрипта

Например, так делает Drupal, WP Super Cache, практически любой современный PHP-сайт, любой сайт, использующий Proxy Pass и отдельный сервер приложения.

Простой человек, портируя настройки mod_rewrite на nginx, непременно найдет HttpRewriteModule и будет писать брутальные конфиги типа

if ($request_method !~ ^(GET|HEAD)$) {
  break;
}
location ^~ /cache {
  internal;
}
if (-f $document_root/cache/index.html) {
  rewrite ^/$ /cache/index.html last;
}
if (-f $document_root/cache/$request_uri) {
  rewrite .* /cache/$request_uri last;
}
if (-f $document_root/cache/$request_uri.html) {
  rewrite .* /cache/$request_uri.html last;
}

(Это мой собственный код из [статьи про кеширование]/post/ruby-on-rails-page-caching/))

К счастью, в современном руководстве HttpRewriteModule ясно написано, что так делать не надо, а надо использовать восхитительную директиву try_files.

Говорят, что она даже немного быстрее, чем каскад if-ов, но я полюбил её не за это. Мне достаточно того, что она лаконична и самодокументируема. Возьмем первый сценарий.

try_files $uri @unicorn;
location @unicorn {
  proxy_pass http://unix:/var/www/apps/myapp/shared/unicorn.sock;
}

Ну разве не красота?

Посмотрим на пример с кешом.

try_files cache/$uri cache/$uri.html cache/$uri/index.html $uri;
location ^~ /cache {
  internal;
}

Наглядно, понятно, без регулярок.

Buy me a coffee Понравился пост? Купи мне кофе