nginx + fastCGI + Django – 在发送到客户端的响应中获取数据损坏

我使用FastCGI在nginx后面运行Django。 我发现,在发送给客户端的一些响应中,随机数据损坏发生在响应中间(中间可能是几百字节左右)。

在这一点上,我已经缩小到nginx的FastCGI处理程序或Django的FastCGI处理程序(即可能是一个漏洞的错误),因为这个问题从来没有发生,当我以独立(即runserver )模式运行Django服务器。 它只发生在FastCGI模式。

其他有趣的趋势:

现在,我不得不通过在响应头中添加一个额外的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个字节。

    解决这种情况的一种方法是:

    • 让nginx和django运行在不同的硬件上(这样你就可以轻松捕获stream量)
    • 捕获客户端的stream量到 – / – > nginx和nginx – / – > django(即使用wireshark)

    一旦你在客户端检测到一个错误(基于sha1),进入networking捕获,查看logging(TCP)stream,并试图找出问题是由nginx生成还是从django(直接) 。