Я запускаю Django за nginx с помощью FastCGI. Я обнаружил, что в некоторых ответах, отправленных клиенту, случайное повреждение данных происходит в середине ответов (может быть пара сотен байтов или около того в середине).
На данный момент я сузил его до ошибки либо в обработчике FastCGI nginx, либо в обработчике FastCGI Django (т.е., вероятно, ошибка в провале), поскольку эта проблема никогда не возникает, когда я запускаю сервер Django в автономном режиме (т.е. runserver
) Режим. Это происходит только в режиме FastCGI.
Другие интересные тенденции:
Это обычно происходит при больших ответах. Когда клиент входит в систему в первый раз, ему отправляется группа фрагментов размером 1 МБ для синхронизации их с БД сервера. После этой первой синхронизации ответы намного меньше (обычно несколько КБ за раз). Кажется, что повреждение всегда происходит с теми фрагментами размером 1 МБ, отправленными в начале.
Это происходит чаще, когда клиент подключается к серверу через локальную сеть (то есть соединение с низкой задержкой и высокой пропускной способностью). Это заставляет меня думать, что в nginx или flup есть какое-то состояние гонки, которое усугубляется увеличением скорости передачи данных.
Прямо сейчас мне пришлось обойти это, поместив дополнительный дайджест SHA1 в заголовок ответа и заставив клиента отклонять ответы, в которых заголовок не соответствует контрольной сумме тела, но это своего рода ужасное решение.
Кто-нибудь еще испытывал что-либо подобное или есть какие-либо указания относительно того, как определить, виноват ли здесь flup или nginx, чтобы я мог сообщить об ошибке соответствующей команде?
Заранее благодарю за любую помощь.
Примечание: я также недавно опубликовал похожую ошибку в lighttpd + FastCGI + Django: https://stackoverflow.com/questions/3714489/lighttpd-fastcgi-django-truncated-response-sent-to-client-due-to-unexpected ... даже при том, что это не одно и то же (усечение или повреждение), начинает казаться, что наиболее распространенным виновником является flup / Django, а не веб-сервер ..
Изменить: я также должен отметить, что такое моя среда:
OSX 10.6.6 на Mac Mini
Python 2.6.1 (Система)
Django 1.3 (из официального архива)
flup 1.0.2 (из Python egg на сайте flup)
nginx + ssl 1.0.0 (из Macports)
РЕДАКТИРОВАТЬ: в ответ на комментарий Ерзика путь кода, который собирает ответ, выглядит (отредактировано для краткости):
# 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-соединения исправил это.
Еще один способ устранить неполадки в этом случае - это:
Как только вы обнаружите ошибку на стороне клиента (на основе sha1), перейдите к захвату сети, посмотрите записанный (TCP) поток и попытайтесь определить, создается ли проблема nginx или она исходит (напрямую) от django. .
Возможно, случайное повреждение происходит только в том случае, если вывод содержит хотя бы один символ UTF-8.
Длина содержимого и длина строки - это не одно и то же, потому что один символ UTF-8 может содержать от 2 до 5 байтов.