ERR_EMPTY_RESPONSE: причины и решения
ERR_EMPTY_RESPONSE означает, что соединение было принято, но сервер отправил обратно ноль байт, вместо нормального HTTP-ответа или хотя бы страницы ошибки. TCP-рукопожатие прошло успешно; то, что должно было ответить на запрос, так этого и не сделало.
Что означает ERR_EMPTY_RESPONSE
Эта ошибка находится позже в жизненном цикле запроса, чем отказанное или зависшее по таймауту соединение. Браузер успешно подключается к серверу, и в запросе по HTTPS TLS-рукопожатие тоже обычно завершается, но после отправки запроса соединение закрывается вообще без строки статуса HTTP, без заголовков и без какого-либо тела. Это отличается от страницы ошибки 500 или 502, которая все же остается полным HTTP-ответом; здесь разбирать нечего, поскольку ничего не пришло обратно.
Это делает ERR_EMPTY_RESPONSE труднее диагностировать со стороны клиента, чем большинство ошибок соединения, поскольку каждый уровень вплоть до транспортного соединения включительно отработал корректно. Неисправность лежит именно в том, что генерирует HTTP-ответ: в процессе приложения, во фреймворке, обрабатывающем запрос, либо в прокси перед ним, закрывшем сокет вместо того, чтобы передать дальше или сгенерировать нормальную страницу ошибки.
Как проявляется ошибка
Chrome показывает "This site can't be reached ... ERR_EMPTY_RESPONSE", как только соединение закрывается без данных. curl сообщает о том же условии прямым текстом:
curl -v https://example.com/api/generate
* Connected to example.com (203.0.113.10) port 443
> GET /api/generate HTTP/1.1
> Host: example.com
*
* Empty reply from server
curl: (52) Empty reply from server
"Empty reply from server" - это точная формулировка curl для этого условия, и она самый ясный сигнал того, что само соединение сработало, а вот то, что должно было сгенерировать ответ, - нет.
Что вызывает ERR_EMPTY_RESPONSE
- Воркер-процесс упал в процессе обработки запроса. Необработанное исключение, уничтожение из-за нехватки памяти или segmentation fault могут закрыть соединение еще до того, как будет записан какой-либо ответ.
- Приложение вышло по таймауту за прокси, который молча закрывает соединение. Некоторые конфигурации обратного прокси закрывают соединение с клиентом без отправки страницы ошибки, когда бэкенд отвечает слишком долго, вместо того чтобы вернуть нормальный 502 или 504.
- На HTTPS-порту отдается обычный HTTP, либо наоборот. Клиент, говорящий по TLS с портом, отдающим обычный HTTP, либо наоборот, не получает валидного ответа, который может разобрать протокольный уровень клиента, и это часто проявляется как пустой ответ, а не как явная ошибка протокола.
- Расширение браузера или локальный прокси вмешивается в ответ. Блокировщики рекламы, расширения приватности либо корпоративный прокси, проверяющий и иногда неправильно обрабатывающий ответ, могут урезать его до полного нуля.
- Проверка работоспособности балансировщика нагрузки помечает бэкенд как нездоровый посреди запроса, закрывая соединение с этим бэкендом до того, как ответ завершится.
Как понять, кто виноват
Сначала отключите расширения браузера или попробуйте окно инкогнито; расширение на стороне клиента - одна из более частых и легко исключаемых причин. Если пустой ответ сохраняется при отключенных расширениях, проверьте со второго устройства или из другой сети, чтобы исключить локальный прокси. Если это стабильно происходит из нескольких внешних мест, причина - в сервере или в сбое приложения. Запуск HTTP-проверки сразу из нескольких контрольных точек подтверждает, является ли пустой ответ общим или привязан к одному клиенту, расширению или сети.
Как исправить ERR_EMPTY_RESPONSE
Если вы посетитель
- Попробуйте окно инкогнито или приватное окно с отключенными расширениями, чтобы исключить блокировщик рекламы или расширение приватности, вмешивающееся в ответ.
- Отключите любой локальный прокси или VPN и повторите попытку, поскольку некоторые перехватывают и иногда неправильно обрабатывают ответы вместо того, чтобы пропускать их насквозь.
- Очистите кэш браузера для сайта; закэшированное поврежденное состояние соединения иногда может проявиться заново именно этой ошибкой при повторной попытке.
- Подождите и перезагрузите страницу. Если причина - упавший воркер-процесс на сервере, супервизор процессов обычно перезапускает его в течение секунд.
Если вы администрируете сайт
- Проверьте логи приложения на предмет падения в то же время, что и провалившийся запрос; необработанное исключение или уничтожение из-за нехватки памяти - самая частая причина, и она обычно оставляет четкий след.
- Убедитесь, что к каждому порту привязан правильный протокол. Проверьте прямой проверкой, что порт 443 действительно отдает TLS, а порт 80 - обычный HTTP, а не наоборот:
curl -v https://example.com:443/ curl -v http://example.com:80/ - Проверьте поведение обратного прокси по таймауту. В nginx бэкенд, превысивший
proxy_read_timeout, все равно должен вернуть 504, поэтому пустой ответ вместо нормальной страницы ошибки обычно означает, что что-то закрывает соединение ниже по стеку. - Проверьте логи балансировщика нагрузки и проверок работоспособности на предмет бэкенда, помеченного как нездоровый примерно в момент сбоя, - это может закрывать активные соединения с этим экземпляром.
- Перезапустите затронутый воркер или сервис, если падение подтверждено, и внимательно следите за логами после перезапуска на предмет повторения той же ошибки.
Как предотвратить ERR_EMPTY_RESPONSE
Падение воркера при определенных условиях, например при конкретной нагрузке запроса или всплеске потребления памяти, может быть достаточно прерывистым, чтобы пройти ручной тест, продолжая при этом периодически проваливаться для реальных посетителей. Постоянный мониторинг HTTP, проверяющий код состояния и тело ответа с регулярным интервалом из 300+ контрольных точек в 158 городах, ловит паттерн пустого ответа, который, скорее всего, пропустила бы разовая ручная проверка, с оповещениями по email, SMS, голосовым звонком, через Slack, Telegram и другие каналы.
Похожие ошибки
- ERR_CONNECTION_RESET тоже досрочно завершает работавшее соединение, но явным сбросом, а не молчаливым закрытием.
- 502 Bad Gateway - это полноценный HTTP-ответ с ошибкой от прокси, в отличие от пустого ответа, который описывает эта ошибка.
- This site can't be reached охватывает весь набор ошибок соединения, которые Chrome группирует под одним заголовком.
Часто задаваемые вопросы
Это то же самое, что ошибка 502?
Нет. 502 - это полный HTTP-ответ со строкой статуса, заголовками и обычно телом, намеренно отправленный прокси. ERR_EMPTY_RESPONSE означает, что вообще не было отправлено никакого HTTP-ответа, только закрытое соединение.
Почему это происходит только на одной конкретной странице?
Страница, стабильно вызывающая эту ошибку, тогда как остальные загружаются нормально, обычно указывает на падение в том пути кода, который использует именно эта страница или эндпоинт API, а не на общую проблему сервера или сети.
Может ли блокировщик рекламы действительно вызвать эту ошибку?
Да. Некоторые блокировщики рекламы и расширения приватности перехватывают и переписывают ответы, и баг или слишком агрессивное правило иногда может урезать легитимный ответ до полного нуля вместо того, чтобы аккуратно его заблокировать.
Означает ли ERR_EMPTY_RESPONSE, что мои данные потерялись?
Не обязательно для запроса GET, но для отправки формы или вызова API, изменяющего данные, прежде чем повторять попытку, проверьте, действительно ли действие завершилось на сервере, поскольку клиент не может определить по пустому ответу, был ли запрос обработан.
Почему curl говорит "Empty reply from server" вместо кода ошибки?
Потому что нет HTTP-ответа, из которого можно было бы прочитать код состояния. Собственная формулировка curl описывает событие на транспортном уровне - закрытое соединение без каких-либо данных, - которое находится на уровень ниже самого протокола HTTP.
Может ли моя собственная сеть закрывать соединение вместо сервера?
Это встречается реже, чем причина на стороне сервера, но случается. Корпоративный прокси или файрвол, завершающий долгие соединения после фиксированного периода простоя, может дать тот же симптом; проверка того же запроса из другой сети быстро это исключает.