我使用FastCGI在nginx后面运行Django。 我发现,在发送给客户端的一些响应中,随机数据损坏发生在响应中间(中间可能是几百字节左右)。
在这一点上,我已经缩小到nginx的FastCGI处理程序或Django的FastCGI处理程序(即可能是一个漏洞的错误),因为这个问题从来没有发生,当我以独立(即runserver )模式运行Django服务器。 它只发生在FastCGI模式。
其他有趣的趋势:
它往往发生在更大的反应。 当客户端第一次login时,会发送一大堆1MB的数据块同步到服务器数据库。 在第一次同步之后,响应要小得多(通常每次几KB)。 腐败似乎总是发生在一开始发送的1MB块上。
当客户端通过LAN连接到服务器(即低延迟,高带宽连接)时,更经常发生这种情况。 这使得我认为在nginx或flup中存在某种竞争条件,并且由于数据速率的提高而加剧。
现在,我不得不通过在响应头中添加一个额外的SHA1摘要来解决这个问题,并且让客户端拒绝头部与主体校验和不匹配的响应,但是这是一种可怕的解决scheme。
有没有其他人经历过这样的事情,或者有任何的指示,以确定是否是错误的flup或nginx,所以我可以提交适当的团队错误?
在此先感谢您的帮助。
注意:我也在lighttpd + FastCGI + Django中发布了一个类似的bug,在这之后: https : //stackoverflow.com/questions/3714489/lighttpd-fastcgi-django-truncated-response-sent-to-client-due-to – 尽pipe这不是一回事(截断与腐败),但它开始看起来像常见的罪魁祸首是flup / Django,而不是Web服务器..
编辑:我也应该注意我的环境是什么:
Mac mini上的OSX 10.6.6
Python 2.6.1(系统)
Django 1.3(官方tarball)
flup 1.0.2(来自python卵上的flup网站)
nginx + ssl 1.0.0(来自Macports)
编辑:为了响应Jerzyk的评论,组装响应的代码path看起来像(编辑为简洁):
# 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
我不认为有可能基于这个内容长度是错误的,AFAIK没有办法将Django HttpResponse对象标记为显式二进制而不是文本。 此外,由于问题只发生间歇性,我不认为这解释,否则大概你会看到它的每一个请求。
编辑@ionelmc:你必须在Django中设置Content-Length – 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
你有什么样的nginxcaching(绕过/ no_cache)指令为fastcgi响应活跃?
在nginx的'1.0.3 Changenotes他们修复了一个响应腐败:
修正:如果“proxy / fastcgi / scgi / uwsgi_cache_bypass”和“proxy / fastcgi / scgi / uwsgi_no_cache”指令值不同,caching的响应可能会中断; 该bug已经出现在0.8.46。
来源: http : //nginx.org/en/CHANGES (1.0.3。节)
如果输出包含至less一个UTF-8字符,偶尔发生的破坏也许会发生。
内容长度和string长度不是一回事,因为一个UTF-8字符可以包含2到5个字节。
解决这种情况的一种方法是:
一旦你在客户端检测到一个错误(基于sha1),进入networking捕获,查看logging(TCP)stream,并试图找出问题是由nginx生成还是从django(直接) 。