- Вопрос или проблема
- Пример 1: Без флагов (break или last)
- Результат:
- Пояснение:
- Пример 2: Вне блока местоположения (break или last)
- Результат:
- Пояснение:
- Пример 3: Внутри блока местоположения – “break”
- Результат:
- Пояснение:
- Пример 4: Внутри блока местоположения – “last”
- Результат:
- Пояснение:
- Сводка:
- Заключительное примечание:
- Ответ или решение
- Теория
- Пример
- Пример 1: Использование флагов вне блока location
- Пример 2: Внутри блока location – "break"
- Пример 3: Внутри блока location – "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
зависит от вашей архитектуры веб-приложения и логики, которую вы стремитесь внедрить.
-
Используйте
last
, когда вам необходимо инициировать новый поиск по конфигурации. Это особенно полезно, когда вы хотите, чтобы ваш запрос после переписывания проходил через новый контекстlocation
, включая возможно новые правила аутентификации или обработки. -
Применяйте
break
, когда вы хотите остаться в текущем контекстеlocation
после переписывания URL. Это может быть полезно, например, когда в рамках одного и того жеlocation
вы хотите управлять контентом только через url без повторного поиска.
Заключение
Понимание и умелое использование флагов break
и last
позволяет эффективно управлять потоками обработки запросов в сервере NGINX. Надеюсь, приведенные выше примеры и объяснения помогут вам определить, какой подход следует использовать в вашей конфигурации для достижения наилучших результатов. Правильная настройка NGINX не только улучшит производительность вашего сайта, но и обеспечит масштабируемость и поддерживаемость вашего проекта в долгосрочной перспективе.