如果网络服务器 returns 错误但仅在上传大文件时请求库引发 ConnectionError

Requests library raises ConnectionError if web-server returns error but only when uploading large file

我是 运行 一个基于 Bottle 框架的网络服务器。该框架公开了一个端点,您可以在其中上传文件。有时,如果磁盘已满,网络服务器应该 return 代码 429 而不是读取文件。出于某种原因,当我上传文件时,如果服务器尝试 return 429 状态代码,则会引发以下异常:

 File "../hooks.py", line 325, in post_video_content
    response = requests.post(url, data=fh)
  File "/usr/local/lib/python2.7/site-packages/requests/api.py", line 110, in post
    return request('post', url, data=data, json=json, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/requests/api.py", line 56, in request
    return session.request(method=method, url=url, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/requests/sessions.py", line 488, in request
    resp = self.send(prep, **send_kwargs)
  File "/usr/local/lib/python2.7/site-packages/requests/sessions.py", line 609, in send
    r = adapter.send(request, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/requests/adapters.py", line 473, in send
    raise ConnectionError(err, request=request)
ConnectionError: ('Connection aborted.', error(32, 'Broken pipe'))

但是如果尝试完全相同的 post 但不是 post 文件我只是 post 一些少量的数据,我实际上从请求中得到了一个响应对象我可以检查状态代码。

重现:

webserver.py

from bottle import Bottle, route, run, request, response, get, post, put, abort

@post('/content')
@authenticate
def content():
    response.status = 429
    return "failed to write incoming movie to temp file (space might be full temporarily)"

run(host="127.0.0.1", port=8080, debug=True)

send_request.py

import requests


# this works and prints the status code
ret = requests.post("127.0.0.1:8080/content", data="sdfsdfsdfsdf")
print ret.status_code

# this part will throw an exception
try:
    with open("~/some_large_video_file.mp4", 'rb') as fh:
        ret = requests.post('127.0.0.1:8080/content', data=fh)
except:
    print traceback.format_exc()

编辑 - 我发现这取决于数据量。如果您尝试 post 类似 10KB 的数据,我们会得到 429 return 代码。我试图弄清楚导致它开始引发异常的限制是什么。

EDIT2 - 所以看起来魔法文件大小介于 117K 和 131K 之间。如果我尝试前者,它会按预期工作,我会收到请求的响应并可以访问状态代码。如果我尝试前者,我会引发异常。

我的问题是:

  1. 为什么会这样?是瓶子里的虫子吗?请求中的错误?为什么我正在 posting 的 size/type 数据会改变响应?
  2. 有什么办法可以解决这个问题吗?我正在尝试将 ConnectionError 异常与服务器关闭相关联,并将 429 响应代码表示磁盘已满。如果我对两者都遇到相同的异常,我无法区分阻止我实施回退以等待磁盘 space 打开
  3. 的情况之间的区别

所以我将此交叉发布到请求 github 问题页面,看起来问题出在请求构建于其上的 httplib 模块中,所以这是一个 no -暂时修复。

参见:https://github.com/kennethreitz/requests/issues/4062