Код состояния 499: что nginx имеет в виду под client closed request
499 в логе nginx означает, что клиент закрыл соединение до того, как nginx закончил отправку ответа. Это не часть официального стандарта HTTP; nginx придумал его исключительно для собственного лога доступа, чтобы операторы могли отличить "клиент сдался" от всех прочих видов сбоя.
Что означает код состояния 499
499 Client Closed Request специфичен для nginx и никогда не определялся ни в одном RFC. Коды выше 99 и ниже 600 в целом зарезервированы под строки статуса HTTP, но 499 - это собственное соглашение nginx, логируемое, когда nginx обнаруживает, что соединение клиента оборвалось, пока он еще ждал ответа от вышестоящего приложения либо еще отправлял тело ответа обратно клиенту. Самая частая реальная форма этого - медленный upstream в сочетании с клиентом, вкладкой браузера либо балансировщиком нагрузки, чей собственный таймаут короче, чем сколько бы времени ни занял сервер, так что клиент вешает трубку первым.
Как это проявляется в логах
Вы никогда не увидите 499 как код состояния, возвращенный какому-либо клиенту, будь то браузер, curl или что-то еще, потому что по определению клиент уже ушел к тому моменту, когда nginx отправил бы его. Он существует только в собственном логе доступа nginx:
10.0.0.12 - - [19/Sep/2026:14:02:11 +0000] "GET /api/report HTTP/1.1" 499 0 "-" "python-requests/2.31"
Размер ответа в 0 байт и время относительно известного времени ответа вашего upstream - две самые полезные детали: 499, стабильно приходящаяся примерно на время таймаута вашего upstream, без какого-либо отправленного ответа, прямо указывает на "бэкенд был слишком медленным, и что-то сдалось ждать".
Что вызывает 499
- Медленное приложение upstream. Бэкенд отвечает дольше, чем готов ждать какой-либо клиент или промежуточное звено, будь то медленный запрос к базе данных, вызов внешнего API либо действительно тяжелые вычисления.
- Таймаут на стороне клиента короче, чем нужно серверу. Закрытая вкладка браузера, мобильное приложение, сдавшееся на нестабильном соединении, либо срабатывание собственного таймаута библиотеки HTTP-клиента прежде, чем приходит ответ.
- Балансировщик нагрузки или промежуточный прокси, выходящий по таймауту первым. Если между реальным конечным пользователем и nginx что-то стоит, его собственный таймаут может вызвать разрыв соединения, который nginx залогирует как 499, даже если реальный конечный пользователь ничего явно не отменял.
- Пользователь уходит со страницы или обновляет ее. Кто-то, уходящий с медленно загружающейся страницы либо нетерпеливо нажимающий обновить, закрывает активное соединение до того, как nginx закончил.
- Несогласованные значения таймаутов по всей цепочке. У клиента, CDN, балансировщика нагрузки и самого nginx может быть свой таймаут, и какой бы из них ни оказался самым коротким, именно он определяет, когда происходит разрыв соединения, независимо от того, как настроены остальные.
Почему это никогда не появляется в браузере
499 - это не ответ, это заметка, которую nginx делает себе о том ответе, который он так и не успел закончить отправлять. Пользователь, чья вкладка породила 499 в ваших логах, вообще ничего не видит: ни страницы ошибки, ни кода состояния, просто страница, переставшая загружаться, либо спиннер, который так и не разрешился, потому что не было никакого ответа для отрисовки браузером. Именно поэтому опора на ошибки, о которых сообщают пользователи, полностью пропускает такие случаи; единственное место, где 499 видна, - это собственный лог доступа сервера.
Как исправить и сократить количество 499
Не существует единственной настройки, устраняющей 499, поскольку лежащая в основе причина - это гонка между тем, что клиент сдается, и тем, что сервер заканчивает работу, и исправление зависит от того, какая сторона этой гонки на самом деле сломана. Начните с выяснения, стабильно ли медленен upstream для затронутого маршрута, либо разрывы соединения группируются вокруг одного клиента, сети или промежуточного звена, поскольку это указывает на разные исправления.
- Сначала исследуйте время ответа upstream, поскольку медленный бэкенд - самая частая лежащая в основе причина. Смотрите, сколько времени затронутые запросы реально заняли на upstream, а не только на то, что nginx залогировал 499.
- Согласуйте значения таймаутов по всей цепочке осознанно, а не оставляйте значение по умолчанию на каждом слое: клиент, CDN, балансировщик нагрузки и собственные
proxy_read_timeoutиproxy_connect_timeoutу nginx должны быть настроены с четким пониманием того, какой из них должен срабатывать первым. - Рассмотрите
proxy_ignore_client_abort, если для вашего приложения важно дать upstream закончить свою работу даже после отключения клиента, например чтобы завершить запись, которую нельзя оставлять наполовину выполненной:
Это не предотвращает саму запись 499 в логе для исходного разрыва соединения; это меняет то, продолжает ли nginx запрос к upstream независимо от этого.proxy_ignore_client_abort on; - Ускорьте саму работу upstream там, где первопричина действительно в медленном эндпоинте, поскольку никакая настройка таймаутов сама по себе не исправит бэкенд, который слишком долго работает; профилируйте конкретные медленные запросы или вызовы за затронутым маршрутом.
- Относитесь к растущей доле 499 как к настоящему сигналу, а не к шуму в логах, который нужно отфильтровать, поскольку это обычно означает, что либо ваше приложение стало медленнее, либо где-то в цепочке не согласована настройка таймаутов.
Как предотвратить превращение этого в сбой
Поскольку 499 никогда не доходит до клиента как видимая ошибка, действительно медленный эндпоинт легко может остаться незамеченным, пока кто-то не прочитает логи доступа, даже пока реальные пользователи тихо отказываются от запросов. Плановая HTTP-проверка измеряет реальное время ответа напрямую у эндпоинта и оповещает при его деградации, ловя замедление, порождающее 499, прежде чем оно перерастет в откровенно проваливающиеся запросы. Мониторинг из нескольких мест также помогает отделить действительно медленный бэкенд от таймаута, срабатывающего только для клиентов на определенном сетевом пути.
Похожие ошибки
См. 504 Gateway Timeout - для стандартного, видимого клиенту эквивалента, когда сам nginx сдается ждать upstream, а не когда клиент сдается первым, обзор 4xx - для стандартного семейства ошибок клиента, и 429 Too Many Requests - для другого вида отказа, привязанного к частоте, а не ко времени.
Часто задаваемые вопросы
Является ли 499 настоящим кодом состояния HTTP?
Нет. Это собственное соглашение логирования nginx для клиента, отключившегося до завершения ответа, и он никогда не отправляется по сети никакому клиенту, поскольку клиент уже ушел к тому моменту, когда он был бы отправлен.
Почему мой инструмент мониторинга никогда не видит 499?
Проверка мониторинга сама является клиентом, и если именно она сдается на медленном ответе, она сообщит о собственной ошибке таймаута, а не о 499, поскольку она так и не получает HTTP-ответ, из которого можно прочитать код состояния. 499 появляется только в собственной записи лога доступа сервера для этого запроса.
Означает ли 499, что мой сервер упал?
Нет. Это конкретно означает, что сервер все еще работал либо собирался начать работу, когда клиент отключился. Падение обычно привело бы к 502 или 500 вместо этого, как только что-то все же ответило бы.
Могу ли я остановить обработку на upstream, когда клиент отключается?
По умолчанию nginx обычно перестает ждать upstream, как только клиент ушел, но точное поведение зависит от настроек вашего прокси; proxy_ignore_client_abort on говорит nginx позволить запросу к upstream продолжаться, а не бросать его.
Какое исправление самое частое для частых 499?
Согласование значений таймаутов между клиентом, любым промежуточным прокси или балансировщиком нагрузки и самим nginx, в сочетании с устранением того, что изначально делает upstream медленным. По отдельности ни то, ни другое обычно не решает устойчивый паттерн.