Django / apache处理不完整/取消的http请求

时间:2015-05-03 22:42:47

标签: python django apache http

使用mod_wsgi在apache上部署django时。它似乎以一种非常奇怪的方式处理不完整或取消的请求。

如果客户取消请求,则取消的请求不会在django上取消,例如,如果您要上传大文件,显然请求的主体将实际流式传输,所以当django正在读取正文时,客户端取消请求,它仍然被处理(只是不完整),并且从未注意到实际的请求取消操作。

当取消请求时,这是来自apache的一个日志示例。 [星期五五月01 22:05:51.055968 2015] [:错误] [pid 31609](70008)部分结果有效但处理不完整:[client 172.31.43.91:3645] mod_wsgi(pid = 31609):无法获取存储桶旅请求。

然后在django代码中,实际的POST字典永远不会被构建(因为请求是不完整的,但它到达django并被处理就像它有数据一样),因此django在尝试获取数据时会失败(和返回缺少的XX字段错误,或逻辑处理它们的方式)

最后,当django尝试回写响应时,它显然会失败,并且客户端已经关闭了连接。

此方案经常发生在用作移动应用程序的REST服务端点的请求上。移动应用程序上传大文件,因此请求在应用程序暂停/关闭时被取消,但服务器似乎总是得到部分请求。

发生这种情况时的完整日志看起来像这样:

[Fri May 01 22:05:51.055968 2015] [:error] [pid 31609](70008)部分结果有效但处理不完整:[client 172.31.43.91:3645] mod_wsgi(pid = 31609):Unable根据要求获得桶旅。

[Fri May 01 22:05:51.062690 2015] [:error] [pid 10580]这里有一些与丢失数据相关的错误消息

[Fri May 01 22:05:51.068790 2015] [:error] [pid 10580] [remote 172.31.43.91:0] mod_wsgi(pid = 10580):处理WSGI脚本' some-path /时发生异常wsgi.py'

[Fri May 01 22:05:51.068827 2015] [:error] [pid 10580] [remote 172.31.43.91:0] IOError:无法写入数据

现在最后一个问题是,有没有办法检测这种不完整的请求并相应地处理它,而不是稍后因缺少必要的数据而失败?

1 个答案:

答案 0 :(得分:4)

在读取请求内容时,如果尚未读取所需的内容长度,那么WSGI层将在调用wsgi.input.read()时引发IOError异常。这可以像在Django中一样传递,或者在更新的版本中更改为名为IOError的不同派生UnreadablePostError异常类型。

当您的应用程序代码没有专门检查损坏的请求内容并处理该异常类型时,它会传播回来并由Django作为无法处理的异常处理。 Django将在那时尝试写出500错误响应。当它由WSGI层写入时,它将在连接关闭时失败,这只能通过实际尝试编写响应来检测。

所以Django不应该给你不完整的POST数据,而应该引发异常。

至于是否有更好的处理方式,答案是否定的。由于WSGI规范基于阻塞模型,因此无法以干净的方式检测和处理丢弃的连接。人们需要切换到ASYNC Web服务器和框架才能更好地处理它,这意味着无法使用WSGI或Django。

FWIW,过去有关mod_wsgi邮件列表中已断开连接问题的讨论。因此,您可以访问Google网上论坛并使用搜索字词搜索列表中的列表,例如“删除连接”和“删除连接”。或者'连接失败'或者'关闭连接'看看你能找到什么。