← Back to blog

NGINX: Request Processing Phases

⚙️ Теория

🔄 Основные фазы

В упрощённой модели HTTP-запрос проходит через ключевые фазы:

  • rewrite
  • access
  • content
  • log

Что делает каждая:

  • rewrite
    меняет URI, аргументы, выполняет rewrite, return, set, if (в рамках rewrite-модуля).
  • access
    проверяет доступ: ACL, auth, limit_req/limit_conn и другие access-проверки.
  • content
    формирует ответ: proxy_pass, fastcgi_pass, uwsgi_pass, return, static file handler.
  • log
    финальная фаза записи логов после завершения обработки запроса.

🧠 Phase engine = state machine

phase engine в NGINX — это конечный автомат, который двигает request по цепочке хендлеров.
Ключевые коды возврата:

  • NGX_OK — переход к следующей фазе;
  • NGX_DECLINED — переход к следующему handler в текущей фазе;
  • NGX_AGAIN/NGX_DONE — временная пауза обработки (возврат в event loop), продолжение позже.

🔁 Internal redirect перезапускает фазы

Когда происходит internal redirect (например rewrite ... last, try_files, error_page), меняется URI/локация.
После этого NGINX заново делает location lookup и повторно запускает фазовый проход уже для нового URI.

Отдельно: в rewrite-модуле такой цикл ограничен 10 итерациями, после чего возвращается 500.


NGX_AGAIN возвращает управление в event loop

NGX_AGAIN означает: операция ещё не завершена, нужно подождать событие I/O.
В этот момент request не блокирует worker: управление уходит в event loop, а обработка продолжится позже при новом событии.


Что нужно уметь объяснить

Почему redirect требует нового location lookup?

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

Что произойдет, если handler вернет NGX_DECLINED?

Это не ошибка и не финальный ответ.
Смысл: «этот handler не обработал запрос». Тогда phase engine передаст request следующему handler в текущей фазе (или пойдёт дальше по фазам, если это ожидаемое поведение для конкретной фазы).

Чем rewrite отличается от content handler?

  • rewrite меняет маршрут запроса (URI/правила), но обычно не генерирует тело ответа;
  • content handler — это место, где реально формируется ответ клиенту (файл, proxy, fastcgi, return и т.д.).

Коротко: rewrite решает куда идти, content решает что отдавать.


🧪 Практика

1. Конфиг с rewrite + proxy_pass

server {
    listen 8080;
    server_name _;

    location /api/ {
        rewrite ^/api/v1/(.*)$ /backend/$1 break;
        proxy_pass http://127.0.0.1:18080;
    }
}

Здесь rewrite ... break меняет URI внутри текущего location, после чего запрос уходит в proxy_pass.


2. Сделать internal redirect

server {
    listen 8080;
    server_name _;

    location /old/ {
        rewrite ^/old/(.*)$ /new/$1 last;
    }

    location /new/ {
        proxy_pass http://127.0.0.1:18080;
    }
}

Ключевой момент: last вызывает internal redirect, поэтому NGINX заново делает location lookup для /new/....


3. Включить и посмотреть debug log

В nginx.conf:

error_log /var/log/nginx/error.log debug;

Для debug-уровня NGINX должен быть собран с опцией --with-debug.

Проверка и reload:

nginx -t && sudo nginx -s reload

Смотреть фазовый проход в логе:

sudo tail -f /var/log/nginx/error.log

И запускать запросы параллельно:

curl -i http://127.0.0.1:8080/api/v1/test
curl -i http://127.0.0.1:8080/old/test

🧾 Вывод

Фазы NGINX удобнее понимать как state machine: каждый хендлер либо продолжает маршрут запроса, либо завершает его, либо откладывает до следующего I/O события.
rewrite и internal redirect влияют на маршрут и могут перезапускать фазовый проход, а content формирует итоговый ответ.
Для диагностики спорных кейсов лучший инструмент — debug-лог, где видно движение запроса по фазам и возвратные коды хендлеров.


📚 Ссылки


Проверка источников

NGINX: Request Processing Phases | Aleksandr Suprun