Переписывание URL в nginx: различие между break и last

Вопрос или проблема

Я не понимаю разницу между break и last (флаги перенаправления). Документация довольно непонятна. Я попытался переключаться между ними в некоторых своих конфигурациях, но не заметил никакой разницы в поведении. Кто-нибудь может объяснить эти флаги более подробно? Желательно с примером, который показывает различия в поведении при переключении одного флага на другой.

У вас могут быть разные наборы правил перенаправления для различных местоположений. Когда модуль перенаправления встречается с last, он прекращает обработку текущего набора, и переписанный запрос передается снова, чтобы найти соответствующее местоположение (и новый набор правил перенаправления). Если правило заканчивается на break, переписывание также прекращается, но переписанный запрос не передается к другому местоположению.

То есть, если есть два места: loc1 и loc2, и имеется правило переписывания в loc1, которое меняет loc1 на loc2 и заканчивается на last, запрос будет переписан и передан на место loc2. Если правило заканчивается на break, оно останется в местах loc1.

Автор предпочёл пример. К тому же, что написал @minaev, это была только часть истории! Итак, начнем…

Пример 1: Без флагов (break или last)

server {
    server_name example.com;
    root 'path/to/somewhere';

    location / {
        echo 'finally matched location /';
    }

    location /notes {
        echo 'finally matched location /notes';
    }

    location /documents {
        echo 'finally matched location /documents';
    }

    rewrite ^/([^/]+.txt)$ /notes/$1;
    rewrite ^/notes/([^/]+.txt)$ /documents/$1;
}

Результат:

# curl example.com/test.txt
finally matched location /documents

Пояснение:

Для rewrite флаги являются необязательными!

Пример 2: Вне блока местоположения (break или last)

server {
    server_name example.com;
    root 'path/to/somewhere';

    location / {
        echo 'finally matched location /';
    }

    location /notes {
        echo 'finally matched location /notes';
    }

    location /documents {
        echo 'finally matched location /documents';
    }

    rewrite ^/([^/]+.txt)$ /notes/$1 break; # или last
    rewrite ^/notes/([^/]+.txt)$ /documents/$1; # это не разбирается
}

Результат:

# curl example.com/test.txt
finally matched location /notes

Пояснение:

Вне блока местоположения как break, так и last ведут себя одинаково…

  • больше не производится разбор условий rewrite
  • внутренний движок Nginx переходит на следующий этап (поиск location соответствия)

Пример 3: Внутри блока местоположения – “break”

server {
    server_name example.com;
    root 'path/to/somewhere';

    location / {
        echo 'finally matched location /';
        rewrite ^/([^/]+.txt)$ /notes/$1 break;
        rewrite ^/notes/([^/]+.txt)$ /documents/$1; # это не разбирается
    }

    location /notes {
        echo 'finally matched location /notes';
    }

    location /documents {
        echo 'finally matched location /documents';
    }
}

Результат:

# curl example.com/test.txt
finally matched location /

Пояснение:

Внутри блока местоположения флаг break делает следующее…

  • прекращается разбор условий rewrite
  • внутренний движок Nginx продолжает разбор текущего блока location

Пример 4: Внутри блока местоположения – “last”

server {
    server_name example.com;
    root 'path/to/somewhere';

    location / {
        echo 'finally matched location /';
        rewrite ^/([^/]+.txt)$ /notes/$1 last;
        rewrite ^/notes/([^/]+.txt)$ /documents/$1;  # это не разбирается
    }

    location /notes {
        echo 'finally matched location /notes';
        rewrite ^/notes/([^/]+.txt)$ /documents/$1;
    }

    location /documents {
        echo 'finally matched location /documents';
    }
}

Результат:

# curl example.com/test.txt
finally matched location /documents

Пояснение:

Внутри блока местоположения флаг last делает следующее…

  • прекращается разбор текущего контекста местоположения условий rewrite
  • внутренний движок Nginx начинает искать другое соответствие местоположения на основе результата rewrite и применяет правило rewrite в этом контексте местоположения

Сводка:

  • Когда условие rewrite с флагом break или last совпадает, Nginx прекращает разбор любых других rewrites!
  • Вне блока местоположения как break, так и last, Nginx выполняет ту же задачу (прекращает обработку дальнейших условий rewrite).
  • Внутри блока местоположения с break Nginx только прекращает обработку дальнейших условий rewrite
  • Внутри блока местоположения с last Nginx прекращает обработку дальнейших условий rewrite и затем начинает искать новое соответствие блоку location!

Заключительное примечание:

Я не включил некоторые дополнительные случаи (например, общие проблемы с редиректами, такие как 500 internal error). Но это выходит за рамки данного вопроса. Возможно, пример 1 тоже выходит за рамки!

Сводка minaev: внутри блока местоположения, когда используется “last”, переписывания прекращаются, и создается новый подзапрос, который будет учитывать все местоположения. Когда используется “break”, переписывания прекращаются, и обработка продолжается в текущем местоположении.

Дополнительно Максим (разработчик команды nginx): с учетом вышеуказанного, вне блока местоположения “break” ведет себя так же, как “last”, так как здесь нет инструкций местоположения для запуска.

Простой и эффективный способ избежать таких проблем — всегда определять “location /”.
https://mailman.nginx.org/pipermail/nginx/2011-October/029931.html

Ответ или решение

В области настройки веб-сервера NGINX директивы URL-переписывания и их флаги играют существенную роль в манипуляции и контроле путей запроса. Особенно важно разобраться в тонкостях работы флагов break и last, чтобы использовать их эффективно в различном контексте конфигурации вашего сервера. Эти флаги, каждые по-своему, определяют, как NGINX должен обрабатывать дальнейшие действия после выполнения правила переписывания.

Теория

Флаг last в контексте переписывания указывает NGINX остановить текущий набор правил и начать новый поиск подходящего блока location. Это фактически создает новый внутренний запрос, что позволяет проконтролировать применение остальных правил в новом контексте.

С другой стороны, флаг break завершает выполнение правил переписывания внутри текущего блока location, но не запускает новый поиск. Это означает, что после выполнения правила с флагом break, сервер NGINX продолжает обработку в рамках текущей конфигурации и текущего контекста location.

Пример

Чтобы иллюстрировать эти различия, рассмотрим несколько примеров конфигурации NGINX:

Пример 1: Использование флагов вне блока location

server {
    server_name example.com;
    root 'path/to/somewhere';

    location / {
        echo 'наконец-то сопоставлен location /';
    }

    location /notes {
        echo 'наконец-то сопоставлен location /notes';
    }

    location /documents {
        echo 'наконец-то сопоставлен location /documents';
    }

    rewrite ^/([^/]+.txt)$ /notes/$1 break; # или last
    rewrite ^/notes/([^/]+.txt)$ /documents/$1; // это не выполняется
}

В этом случае, вне контекста location, как last, так и break фактически останавливают дальнейшую обработку. Однако, важным моментом является то, что после выполнения правила с break или last будет применен новый поиск в рамках всей конфигурации сервера.

Пример 2: Внутри блока location – "break"

server {
    server_name example.com;
    root 'path/to/somewhere';

    location / {
        echo 'наконец-то сопоставлен location /';
        rewrite ^/([^/]+.txt)$ /notes/$1 break;
        rewrite ^/notes/([^/]+.txt)$ /documents/$1; // это не выполняется
    }

    location /notes {
        echo 'наконец-то сопоставлен location /notes';
    }

    location /documents {
        echo 'наконец-то сопоставлен location /documents';
    }
}

При использовании флага break внутри блока location, NGINX после выполнения правила переписывания break не начнет новый поиск. Он продолжит дальнейшее выполнение оставшихся инструкций в текущем блоке.

Пример 3: Внутри блока location – "last"

server {
    server_name example.com;
    root 'path/to/somewhere';

    location / {
        echo 'наконец-то сопоставлен location /';
        rewrite ^/([^/]+.txt)$ /notes/$1 last;
        rewrite ^/notes/([^/]+.txt)$ /documents/$1;  // это не выполняется
    }

    location /notes {
        echo 'наконец-то сопоставлен location /notes';
        rewrite ^/notes/([^/]+.txt)$ /documents/$1;
    }

    location /documents {
        echo 'наконец-то сопоставлен location /documents';
    }
}

При использовании флага last в рамках блока location, NGINX завершает обработку текущих правил и начинает новый поиск подходящего блока location, на основании результата переписывания rewrite.

Применение

Правильный выбор между break и last зависит от вашей архитектуры веб-приложения и логики, которую вы стремитесь внедрить.

  1. Используйте last, когда вам необходимо инициировать новый поиск по конфигурации. Это особенно полезно, когда вы хотите, чтобы ваш запрос после переписывания проходил через новый контекст location, включая возможно новые правила аутентификации или обработки.

  2. Применяйте break, когда вы хотите остаться в текущем контексте location после переписывания URL. Это может быть полезно, например, когда в рамках одного и того же location вы хотите управлять контентом только через url без повторного поиска.

Заключение

Понимание и умелое использование флагов break и last позволяет эффективно управлять потоками обработки запросов в сервере NGINX. Надеюсь, приведенные выше примеры и объяснения помогут вам определить, какой подход следует использовать в вашей конфигурации для достижения наилучших результатов. Правильная настройка NGINX не только улучшит производительность вашего сайта, но и обеспечит масштабируемость и поддерживаемость вашего проекта в долгосрочной перспективе.

Оцените материал
Добавить комментарий

Капча загружается...