当 django 使用 mod_wsgi 部署在 apache 上时。它似乎以一种非常奇怪的方式处理未完成或取消的请求。
如果客户端取消了请求,被取消的请求在django上并没有被取消,比如你上传了一个大文件,显然请求的body实际上会被流式传输,所以django在读取body的同时,和客户端取消请求,它仍在处理中(只是未完成)并且从未注意到实际的请求取消操作。
这是一个来自 apache 的日志示例,当请求被取消时。 [Fri May 01 22:05:51.055968 2015] [:error] [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: 写入数据失败
现在最后一个问题是,有没有办法检测这种不完整的请求并相应地处理它,而不是稍后因缺少所需数据而失败?
最佳答案
读取请求内容时,如果没有读取到所需长度的内容,则WSGI层会在调用wsgi.input.read()
时抛出一个IOError
异常。这可能会像在 Django 中一样传递,或者在更新的版本中更改为不同的派生 IOError
异常类型,称为 UnreadablePostError
。
当您的应用程序代码没有专门检查损坏的请求内容并处理该异常类型时,它会向上传播并由 Django 作为未处理的异常进行处理。此时 Django 将尝试编写 500 错误响应。当它由 WSGI 层写入时,它将失败,因为连接已关闭,这只能通过实际尝试写入响应才能检测到。
因此 Django 不应为您提供不完整的 POST 数据,而应该引发异常。
至于是否有更好的处理方式,答案是否定的。由于 WSGI 规范基于阻塞模型,以干净的方式检测和处理断开的连接实际上是不可能的。需要切换到 ASYNC 网络服务器和框架才能更好地处理它,这意味着无法使用 WSGI 或 Django。
FWIW,过去在 mod_wsgi 邮件列表上讨论过连接断开的问题。因此,您可能会转到 Google 网上论坛并使用“断开连接”或“连接失败”或“关闭连接”等搜索词在存档中搜索列表,然后查看可以找到的内容。
关于python - Django/apache 处理不完整/取消的 http 请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30020226/