Requests: max-retries-exceeded 异常令人困惑

创建于 2013-02-15  ·  39评论  ·  资料来源: psf/requests

你好,
例如:

>>> requests.get('http://localhost:1111')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "requests/api.py", line 55, in get
    return request('get', url, **kwargs)
  File "requests/api.py", line 44, in request
    return session.request(method=method, url=url, **kwargs)
  File "requests/sessions.py", line 312, in request
    resp = self.send(prep, **send_kwargs)
  File "requests/sessions.py", line 413, in send
    r = adapter.send(request, **kwargs)
  File "requests/adapters.py", line 223, in send
    raise ConnectionError(e)
requests.exceptions.ConnectionError: HTTPConnectionPool(host='localhost', port=1111): Max retries exceeded with url: / (Caused by <class 'socket.error'>: [Errno 61] Connection refused)

(假设没有监听端口 1111)

异常显示“超过最大重试次数”。 我发现这很令人困惑,因为我没有指定任何与重试相关的参数。 事实上,我找不到任何关于指定重试次数的文档。 经过代码,似乎urllib3是底层传输,并且使用max_retries = 0调用它(因此实际上没有重试)。 而 requests 只是包装了异常。 所以这是可以理解的,但它混淆了最终用户(最终开发人员)? 我认为这里应该做一些更好的事情,特别是考虑到很容易出现这个错误。

Feature Request

最有用的评论

我同意这很令人困惑。 请求从不重试(它为 urllib3 的 HTTPConnectionPool 设置了 retries=0),因此如果没有 HTTPConnectionPool/MaxRetryError 东西,错误会更加明显。 直到现在我才意识到请求使用了 urllib3,当我不得不深入研究这两个库的源代码以帮助我弄清楚它正在执行多少次重试时:

ConnectionError(MaxRetryError("HTTPSConnectionPool(host='api.venere.com', port=443): \
    Max retries exceeded with url: /xhi-1.0/services/XHI_HotelAvail.json (\
    Caused by <class 'socket.error'>: [Errno 10054] \
    An existing connection was forcibly closed by the remote host)",),)

理想情况下,异常看起来像这样:

ConnectionError(<class 'socket.error'>: [Errno 10054] \
    An existing connection was forcibly closed by the remote host))

所有39条评论

为方便用户,请求包装了异常。 尽管回溯具有误导性,但原始异常是消息的一部分。 我会考虑如何改进这一点。

我认为需要自动重试以忽略一些错误

我同意这很令人困惑。 请求从不重试(它为 urllib3 的 HTTPConnectionPool 设置了 retries=0),因此如果没有 HTTPConnectionPool/MaxRetryError 东西,错误会更加明显。 直到现在我才意识到请求使用了 urllib3,当我不得不深入研究这两个库的源代码以帮助我弄清楚它正在执行多少次重试时:

ConnectionError(MaxRetryError("HTTPSConnectionPool(host='api.venere.com', port=443): \
    Max retries exceeded with url: /xhi-1.0/services/XHI_HotelAvail.json (\
    Caused by <class 'socket.error'>: [Errno 10054] \
    An existing connection was forcibly closed by the remote host)",),)

理想情况下,异常看起来像这样:

ConnectionError(<class 'socket.error'>: [Errno 10054] \
    An existing connection was forcibly closed by the remote host))

那将是理想的。 问题在于像我们一样包装这些异常。 它们提供了很好的 API,但调试体验很差。 我有一个关于如何修复它并保留所有信息的想法

我们还需要考虑用户 _does_ configure 重试的情况,在这种情况下,此异常是合适的。

@Lukasa ,我不确定您是否需要考虑这一点在这里说请求明确不应该支持重试作为其 API 的一部分。

是的,但没有办法阻止用户实际这样做。

根据记录,我的计划是尽可能向下遍历到最低级别的异常并使用它。 @benhoyt示例的问题在于,我们似乎无法使用套接字错误异常。 (只是看他粘贴的内容。我还没有尝试复制它并玩它。)

@gabor的例子实际上使这很容易重现。 捕获引发的异常,我执行了以下操作:

>>> e
ConnectionError(MaxRetryError("HTTPConnectionPool(host='localhost', port=1111): Max retries exceeded with url: / (Caused by <class 'socket.error'>: [Errno 111] Connection refused)",),)
>>> e.args
(MaxRetryError("HTTPConnectionPool(host='localhost', port=1111): Max retries exceeded with url: / (Caused by <class 'socket.error'>: [Errno 111] Connection refused)",),)
>>> e.args[0].args
("HTTPConnectionPool(host='localhost', port=1111): Max retries exceeded with url: / (Caused by <class 'socket.error'>: [Errno 111] Connection refused)",)
>>> e.args[0].args[0]
"HTTPConnectionPool(host='localhost', port=1111): Max retries exceeded with url: / (Caused by <class 'socket.error'>: [Errno 111] Connection refused)"
>>> isinstance(e.args[0].args[0], str)
True

所以我们能做的最好的事情就是只使用存储在e.args[0].args[0]的消息,这也可能会造成混淆,但可能不如@benhoyt遇到的那样。 无论哪种方式,我们都不会解析错误消息来尝试获取更多或更少的详细信息,因为这完全是疯狂的。

@sigmavirus24 ,我同意异常中的字符串解析是一个糟糕的主意。 然而,urllib3 的 MaxRetryError 已经暴露了一个reason属性,它包含底层异常(见源代码)。 所以你可以用e.args[0].reason得到你想要的。

所以继续上面的例子, e.args[0].reasonsocket.error一个实例:

>>> requests.get('http://localhost:1111')
Traceback (most recent call last):
  ...
requests.exceptions.ConnectionError: HTTPConnectionPool(host='localhost', port=1111): Max retries exceeded with url: / (Caused by <class 'socket.error'>: [Errno 10061] No connection could be made because the target machine actively refused it)
>>> e = sys.last_value
>>> e
ConnectionError(MaxRetryError("HTTPConnectionPool(host='localhost', port=1111): Max retries exceeded with url: / (Caused by <class 'socket.error'>: [Errno 10061] No connection could be made because the target machine actively refused it)",),)
>>> e.args[0]
MaxRetryError("HTTPConnectionPool(host='localhost', port=1111): Max retries exceeded with url: / (Caused by <class 'socket.error'>: [Errno 10061] No connection could be made because the target machine actively refused it)",)
>>> e.args[0].reason
error(10061, 'No connection could be made because the target machine actively refused it')

不错的收获@benhoyt。 我对 urllib3 并不像我想的那样熟悉。

如果它真的像你展示的那样,即。
requests.exceptions.ConnectionError: HTTPConnectionPool(host='localhost', port=1111): Max retries exceeded with url: / (Caused by <class 'socket.error'>: [Errno 61] Connection refused)

那么我就无法梦想更好的例外,真的。

@piotr-dobrogost,主要问题(对我来说)是它谈论“超过最大重试次数”,而根本不涉及重试。 起初我以为是我使用的网络服务这么说,所以我联系了他们。 然后,进一步挖掘,我发现这是一个 urllib3 怪癖。 所以你可以看到混乱。

您是否错过了异常的(Caused by <class 'socket.error'>: [Errno 61] Connection refused)部分?

是的,你是对的——一切都在那里。 但正如我所提到的,一开始我错过了,因为 MaxRetryError 是一个红鲱鱼。

这个最大重试次数总是让我发疯。 有人介意我潜入看看我是否不能将 PR 放在一起来压缩重试消息吗?

我并不是想凭空出现,但我在 Cloudant 所做的 Python 工作中使用了大量的请求。 我们得到包含重试内容的页面,这可能是一个红鲱鱼。

答案是_也许_。

问题是,虽然默认情况下我们不执行任何重试,但您可以将请求配置为自动重试失败的请求。 在这些情况下,我们包装的MaxRetryError是完全合理的。 如果你能想出一个解决方案,在它应该存在的时候将MaxRetryError留在原处,但在你可以保证没有重试尝试时将其删除,我们会考虑它。 =)

@Lukasa谢谢,我正在这里的积压工作中刷新自己。 如果我有机会潜入,我一定会伸出援手。

在我看来,更改的正确位置似乎在 urllib3 中? 在自动重试的上下文中引发 MaxRetryError 是有意义的,但在零重试的情况下(可能是幼稚的请求体验),它可能会令人困惑。

在 urllib3 中,似乎可以通过请求在此处触发令人困惑的错误。 仅在retries==0 and max_retries!=0时引发 MaxRetryError 几乎会很好。 如果max_retries==0引发了一个普通的RequestError

我看到请求使用的 urllib3 存在于一个包含的包中——只是好奇,为什么会这样? 无论如何,这些只是我想扔掉的一些想法。 我仍在追赶代码库。

该修复程序是否属于 urllib3 完全取决于 @shazow。 鉴于默认情况下 urllib3 _does_ 重试(3 次 IIRC),他可能希望保持 urllib3 的行为不变。 Ping 他以获取他的输入。

我们供应 urllib3 以避免一些依赖性问题。 从本质上讲,这意味着我们始终针对已知版本的 urllib3 进行操作。 如果你想要详细的细节,这已经在 #1384 和 #1812 中以令人难以忍受的长度进行了讨论。

呸,但内容丰富。 @shazow这些只是我的一些想法——引发 RequestError 而不是 MaxRetryError 如上所述。 我真的认为我在查看urlopen后更好地理解了 MaxRetryError 。

双重编辑:真的甚至只是一个 kwarg 这样一个人可以raise MaxRetryError(retries=0)并更改retries==0上的消息。

retries=False会完全禁用重试并始终引发原始异常而不是MaxRetryError怎么样?

能够区分要求 urlopen 不重试和让它在重试次数上倒计时到 0 会很有用。 当您没有要求重试时,看到 MaxRetryError 令人不快。

如果有人想为此进行补丁+测试,将不胜感激。 :)

@shazow很棒,如果我能找到周期,我会很高兴。 有什么我就ping。

\O/

^我想知道是否有任何补丁发布? 这个问题好像有一年了。

据我所知没有。 =)

retries=False应该从 v1.9 开始引发原始异常,没有包装。

@kevinburke 的想法?

需要多一点时间

凯文·伯克
电话:925.271.7005 | 二十毫秒.com

2014 年 10 月 5 日星期日上午 10:37,Ian Cordasco通知@github.com
写道:

@kevinburke https://github.com/kevinburke想法?


直接回复此邮件或在 GitHub 上查看
https://github.com/kennethreitz/requests/issues/1198#issuecomment -57945403
.

是的,这已经解决了,我想

requests.get('http://localhost:11211')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "requests/api.py", line 60, in get
    return request('get', url, **kwargs)
  File "requests/api.py", line 49, in request
    return session.request(method=method, url=url, **kwargs)
  File "requests/sessions.py", line 457, in request
    resp = self.send(prep, **send_kwargs)
  File "requests/sessions.py", line 569, in send
    r = adapter.send(request, **kwargs)
  File "requests/adapters.py", line 407, in send
    raise ConnectionError(err, request=request)
requests.exceptions.ConnectionError: ('Connection aborted.', error(61, 'Connection refused'))

您能否告诉我这是如何解决的,因为我最后也遇到了连接被拒绝的问题。 在我的 python 脚本中,我试图连接 RPC 服务器

@SiddheshS这个问题是通过改写一些例外来解决的:它与实际的连接被拒绝错误无关。 要寻求有关问题的帮助,您应该考虑使用Stack Overflow

我遇到了同样的问题。 它偶尔发生。 如何修复,有人可以帮助我吗? 。谢谢。

requests.exceptions.ConnectionError: HTTPSConnectionPool(host='api.xxxx.com', port=443): Max retries exceeded with url: /v2/goods/?category=0&sort_type=2&page_size=3&page_num=13&t=0&count=110 (Caused通过 NewConnectionError(': 建立新连接失败: [Errno 110] 连接超时',))
回溯(最近一次调用最后一次):
文件“test.py”,第 335 行,在
主要的()
文件“test.py”,第 290 行,在主目录中
结果 = get_goods_info()
文件“test.py”,第 67 行,在 get_goods_info 中
结果 = requests.get(url)
文件“/usr/local/lib/python2.7/site-packages/requests/api.py”,第69行,在get
返回请求('get', url, params=params, *_kwargs)
文件“/usr/local/lib/python2.7/site-packages/requests/api.py”,第50行,请求
response = session.request(method=method, url=url, *_kwargs)
文件“/usr/local/lib/python2.7/site-packages/requests/sessions.py”,第468行,请求
resp = self.send(prep, *_send_kwargs)
文件“/usr/local/lib/python2.7/site-packages/requests/sessions.py”,第576行,发送
r =adapter.send(request, *_kwargs)
文件“/usr/local/lib/python2.7/site-packages/requests/adapters.py”,第423行,发送
引发 ConnectionError(e, request=request)

@nkjulia连接尝试超时,这表明远程服务器过载或您的连接超时时间太短。

我也被这个误导了......

@kevinburke在收到连接拒绝错误后您的问题是如何解决的? 能不能请小伙伴指教一下。 TIA

忽略我的帖子伙伴。 我的机器中有多个版本的 python,因此它无法选择正确的版本并抛出错误。 发布此想法可能对某人有所帮助。

我遇到了同样的问题。 它偶尔发生。 如何修复,有人可以帮助我吗? 。谢谢。

requests.exceptions.ConnectionError: HTTPSConnectionPool(host='api.xxxx.com', port=443): Max retries exceeded with url: /v2/goods/?category=0&sort_type=2&page_size=3&page_num=13&t=0&count=110 (Caused通过 NewConnectionError(': 建立新连接失败: [Errno 110] 连接超时',))
回溯(最近一次调用最后一次):
文件“test.py”,第 335 行,在
主要的()
文件“test.py”,第 290 行,在主目录中
结果 = get_goods_info()
文件“test.py”,第 67 行,在 get_goods_info 中
结果 = requests.get(url)
文件“/usr/local/lib/python2.7/site-packages/requests/api.py”,第69行,在get
返回请求('get', url, params=params, *_kwargs)
文件“/usr/local/lib/python2.7/site-packages/requests/api.py”,第50行,请求
response = session.request(method=method, url=url, *_kwargs)
文件“/usr/local/lib/python2.7/site-packages/requests/sessions.py”,第468行,请求
resp = self.send(prep, *_send_kwargs)
文件“/usr/local/lib/python2.7/site-packages/requests/sessions.py”,第576行,发送
r =adapter.send(request, *_kwargs)
文件“/usr/local/lib/python2.7/site-packages/requests/adapters.py”,第423行,发送
引发 ConnectionError(e, request=request)

如果这个问题已经解决,请给我一些建议。

此页面是否有帮助?
0 / 5 - 0 等级