Назад | Перейти на главную страницу

nginx + fastCGI + Django - получение повреждения данных в ответах, отправленных клиенту

Я запускаю Django за nginx с помощью FastCGI. Я обнаружил, что в некоторых ответах, отправленных клиенту, случайное повреждение данных происходит в середине ответов (может быть пара сотен байтов или около того в середине).

На данный момент я сузил его до ошибки либо в обработчике FastCGI nginx, либо в обработчике FastCGI Django (т.е., вероятно, ошибка в провале), поскольку эта проблема никогда не возникает, когда я запускаю сервер Django в автономном режиме (т.е. runserver) Режим. Это происходит только в режиме FastCGI.

Другие интересные тенденции:

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

Кто-нибудь еще испытывал что-либо подобное или есть какие-либо указания относительно того, как определить, виноват ли здесь flup или nginx, чтобы я мог сообщить об ошибке соответствующей команде?

Заранее благодарю за любую помощь.

Примечание: я также недавно опубликовал похожую ошибку в lighttpd + FastCGI + Django: https://stackoverflow.com/questions/3714489/lighttpd-fastcgi-django-truncated-response-sent-to-client-due-to-unexpected ... даже при том, что это не одно и то же (усечение или повреждение), начинает казаться, что наиболее распространенным виновником является flup / Django, а не веб-сервер ..

Изменить: я также должен отметить, что такое моя среда:

РЕДАКТИРОВАТЬ: в ответ на комментарий Ерзика путь кода, который собирает ответ, выглядит (отредактировано для краткости):

# This returns an objc NSData object, which is an array.array 
# when pushed through the PyObjC bridge
ret = handler( request ) 

response = HttpResponse( ret )
response[ "Content-Length" ] = len( ret )
return response

Я не думаю, что возможно, что Content-Length ошибочен на основе этого, и AFAIK нет возможности пометить объект Django HttpResponse как явно двоичный, а не текстовый. Кроме того, поскольку проблема возникает периодически, я не думаю, что это объясняет ее, иначе, вероятно, вы увидите ее при каждом запросе.

ИЗМЕНИТЬ @ionelmc: вы должны установить Content-Length в Django - nginx не устанавливает это для вас, как в приведенном ниже примере, как только я отключил настройку Content-Length явно:

$ curl -i http://localhost/io/ping
HTTP/1.1 200 OK
Server: nginx/1.0.0
Date: Thu, 23 Jun 2011 13:37:14 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive

AKSJDHAKLSJDHKLJAHSD

Есть ли у вас какая-либо директива кеширования nginx (bypass / no_cache), активная для ответов fastcgi?

В изменениях nginx 1.0.3 исправлено повреждение ответа:

Исправление: кешированный ответ мог не работать, если значения директив proxy / fastcgi / scgi / uwsgi_cache_bypass и proxy / fastcgi / scgi / uwsgi_no_cache были разными; ошибка появилась в 0.8.46.

Источник: http://nginx.org/en/CHANGES (1.0.3. Раздел)

я имел очень похожая проблема который мучил меня, пока у меня была эта установка. Как и вы, я использую FastCGI, Nginx и macOS и обнаружил случайное повреждение в середине больших запросов (это было около 2% запросов документа размером 1,5 МБ).

Я смог решить свою проблему, переключившись на сокеты Unix через TCP для соединения FastCGI между PHP-FPM (в моем случае) и Nginx. Я не знаю, какая часть головоломки ответственна за повреждение, но отказ от внутреннего TCP-соединения исправил это.

Еще один способ устранить неполадки в этом случае - это:

  • иметь nginx и django, работающие на другом оборудовании (чтобы вы могли легко захватывать трафик)
  • захватить трафик от клиента к - / -> nginx и nginx - / -> django (т.е. использовать wirehark)

Как только вы обнаружите ошибку на стороне клиента (на основе sha1), перейдите к захвату сети, посмотрите записанный (TCP) поток и попытайтесь определить, создается ли проблема nginx или она исходит (напрямую) от django. .

Возможно, случайное повреждение происходит только в том случае, если вывод содержит хотя бы один символ UTF-8.

Длина содержимого и длина строки - это не одно и то же, потому что один символ UTF-8 может содержать от 2 до 5 байтов.