【问题标题】:Handling HTTP chunked encoding with django使用 django 处理 HTTP 分块编码
【发布时间】:2012-08-18 22:27:30
【问题描述】:

我在处理 http 分块传输编码时遇到问题。

我正在使用:

  • 阿帕奇。
  • mod_wsgi 插件。
  • django.

django 只能处理带有 content-length 头域的常规 http 请求,但在处理 TE(Transfer-Encoding)、chunked 或 gzip 时,它会返回一个空结果。

我正在考虑两种方法:

  1. 对 django.wsgi python 文件进行一些修改
  2. 在 django 中添加一些中间件 python 文件,以拦截任何分块的 http 请求,将其转换为带有 content-length 头字段的 requelar http 请求,然后将其传递给 django,它可以很好地处理它。

任何人都可以提供以上 2 个选项中的任何一个(当然欢迎更多选项)

谢谢!


这是格雷厄姆第一次回答后对我的问题的延伸:

首先,感谢您的快速回复。使用的客户端是 Axis,它是另一家公司与我们的系统通信的一部分。我设置了WSGIChunkedRequest On,我还对我的 wsgi 包装器进行了一些修改,如下所示:

def application(environ, start_response):

    if environ.get("mod_wsgi.input_chunked") == "1":
        stream = environ["wsgi.input"]
        print stream
        print 'type: ', type(stream)
        length = 0
        for byte in stream:
            length+=1
        #print length    
        environ["CONTENT_LENGTH"] = len(stream.read(length))

    django_application = get_wsgi_application()
    return django_application(environ, start_response)

但它给了我那些错误(从 apache 的 error.log 文件中提取):

[Sat Aug 25 17:26:07 2012] [error] <mod_wsgi.Input object at 0xb6c35390>
[Sat Aug 25 17:26:07 2012] [error] type:  <type 'mod_wsgi.Input'>
[Sat Aug 25 17:26:08 2012] [error] [client xxxxxxxxxxxxx] mod_wsgi (pid=27210): Exception occurred processing WSGI script '/..../wsgi.py'.
[Sat Aug 25 17:26:08 2012] [error] [client xxxxxxxxxxxxx] Traceback (most recent call last):
[Sat Aug 25 17:26:08 2012] [error] [client xxxxxxxxxxxxx]   File "/..../wsgi.py", line 57, in application
[Sat Aug 25 17:26:08 2012] [error] [client xxxxxxxxxxxxx]     for byte in stream:
[Sat Aug 25 17:26:08 2012] [error] [client xxxxxxxxxxxxx] IOError: request data read error

我做错了什么?!

【问题讨论】:

  • 还要补充一点:environ["CONTENT_LENGTH"] = len(stream.read()) 效果不佳,并给出了与IOError: request data read error 相同的错误..谢谢!

标签: django apache mod-wsgi wsgi chunked-encoding


【解决方案1】:

这不是 Django 问题。这是 WSGI 规范本身的限制,因为 WSGI 规范通过要求请求的 CONTENT_LENGTH 值来禁止使用分块的请求内容。

当使用 mod_wsgi 时,有一个开关可以启用对分块请求内容的非标准支持,但这意味着您的应用程序不兼容 WSGI,而且它需要自定义 Web 应用程序或 WSGI 包装器,因为它仍然不会使用 Django。

mod_wsgi 中允许分块请求内容的选项是:

WSGIChunkedRequest On

你的 WSGI 包装器应该调用 wsgi.input.read() 来获取全部内容,用它创建一个 StringIO 实例并用它来替换 wsgi.input,然后在调用之前添加一个具有实际长度的新 CONTENT_LENGTH 值到环境中。应用。

请注意这是危险的,因为您不知道发送了多少数据。

您使用的是什么客户端,只支持分块请求内容?


更新 1

您的代码因多种原因而损坏。你应该使用类似的东西:

import StringIO

django_application = get_wsgi_application()

def application(environ, start_response):

    if environ.get("mod_wsgi.input_chunked") == "1":
        stream = environ["wsgi.input"]
        data = stream.read()   
        environ["CONTENT_LENGTH"] = str(len(data))
        environ["wsgi.input"] = StringIO.StringIO(data)

    return django_application(environ, start_response)

请注意,这对 gzip 的请求内容没有帮助。您将需要额外检查以查看内容编码何时是压缩数据,然后执行与上述相同的操作。这是因为当 Apache 解压缩数据时,内容长度会发生变化,您需要重新计算它。

【讨论】:

  • 请注意,该问题已根据此答案进行了编辑。
  • 您的代码因各种原因而损坏。摆脱你的 for 循环和损坏的长度计算,这实际上是计算行数而不是字符数。您只需要'data = stream.read()' 并从那里开始。您对 Django 的每个 Web 请求调用 get_wsgi_application() 也被破坏了。我会修改我的答案。
  • 似乎我们非常接近答案。我复制了您的代码,将其粘贴到我的包装器中;它显示没有问题,但抱怨这一行data = stream.read(),并出现此错误:IOError: request data read error(从 apache 的 error.log 复制)。从其他代码中,我知道 stream.read() 应该正常工作,潜在的问题是什么?!谢谢!
  • 如果您使用的是守护程序模式,则问题尚未得到解决。被推迟到 mod_wsgi 4.0。所以只能使用嵌入式模式。 groups.google.com/forum/?fromgroups=#!topic/modwsgi/Rk-cXTGSCHQ
  • 在您的最后 2 个 cmets 之前,我已经从 3.3 升级到 3.4,但问题仍然存在。是的,我使用此指令WSGIDaemonProcess 在守护程序模式下使用 mod_wsgi。我会尝试以嵌入式模式运行它并回复您。感谢 Graham 提供的所有帮助!
【解决方案2】:

现在一切顺利,问题出在守护程序模式,因为它不适用于分块的 http 流量,可能在 mod_wsgi 4 中——根据 Graham Dumpleton。因此,如果您遇到此问题,请将 mod_wsgi 切换到嵌入式模式。

作为对 wsgi 包装器中 Graham 代码的修改,有 2 个选项可以读取缓冲在环境变量中的流:

第一个:

try:
    while True:
        data+= stream.next()
except:
    print 'Done with reading the stream ...'

第二个:

try:
   data+= stream.read()
except:
   print 'Done with reading the stream ...' 

第一个代码存根,能够在守护程序模式下读取缓冲区但在某处停止,并且程序没有继续运行(这让我有点困惑,因为我希望看到它运行良好),而其他代码存根,因 IOError 而崩溃,并且仅在嵌入式模式下工作。

还要补充一点,从 3.3 升级到 3.4 并没有解决问题,所以您必须切换到嵌入式模式。

这些是我的结果和观察。如果您有任何 cmet、补充或更正,请不要犹豫。

谢谢!

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-10-21
  • 1970-01-01
  • 2016-04-08
  • 1970-01-01
  • 2018-07-14
  • 2010-09-22
相关资源
最近更新 更多