我可以为requests.request设置max_retries吗?

355 投票
6 回答
347941 浏览
提问于 2025-04-17 19:12

Python的requests模块使用起来简单又优雅,但有一点让我困扰。

有时候会出现一个叫做requests.exception.ConnectionError的错误,错误信息可能是这样的:

Max retries exceeded with url: ...

这意味着requests可能会尝试多次访问数据。但是在文档中根本没有提到过这种可能性。我查看了源代码,也没有找到可以修改默认值(可能是0)的地方。

那么,有没有办法设置requests的最大重试次数呢?

6 个回答

68

注意哦,Martijn Pieters 的回答不适用于 1.2.1 版本及以上。你不能在全局范围内设置它,除非对库进行修改。

你可以试试这样做:

import requests
from requests.adapters import HTTPAdapter

s = requests.Session()
s.mount('http://www.github.com', HTTPAdapter(max_retries=5))
s.mount('https://www.github.com', HTTPAdapter(max_retries=5))
487

这段代码不仅会改变 max_retries 的值,还会启用一种叫做“退避策略”的机制。这种机制会让所有 http:// 地址在重试之前先等待一段时间(最多重试5次):

import requests

from requests.adapters import HTTPAdapter, Retry

s = requests.Session()

retries = Retry(total=5,
                backoff_factor=0.1,
                status_forcelist=[ 500, 502, 503, 504 ])

s.mount('http://', HTTPAdapter(max_retries=retries))

s.get('http://httpstat.us/500')

根据 关于 Retry 的文档:如果 backoff_factor 设置为 0.1,那么在重试之间会等待 [0.05秒, 0.1秒, 0.2秒, 0.4秒, ...]。如果返回的状态码是 500502503504,也会强制进行重试。

还有其他一些选项可以让 Retry 更加灵活:

  • total – 允许的总重试次数。
  • connect – 针对连接相关错误的重试次数。
  • read – 针对读取错误的重试次数。
  • redirect – 允许的重定向次数。
  • method_whitelist – 需要重试的 HTTP 方法的集合(大写)。
  • status_forcelist – 需要强制重试的 HTTP 状态码集合。
  • backoff_factor – 在尝试之间应用的退避因子。
  • raise_on_redirect – 如果重定向次数用完,是否抛出 MaxRetryError,还是返回一个状态码在 3xx 范围内的响应。
  • raise_on_status – 和 raise_on_redirect 类似:如果状态码在 status_forcelist 范围内且重试次数用完,是否抛出异常或返回响应。

注意: raise_on_status 是相对较新的功能,还没有在 urllib3 或 requests 的版本中发布。 raise_on_status 这个参数在 Python 3.6 版本的标准库中出现过。

如果想让请求在特定的 HTTP 状态码上重试,可以使用 status_forcelist。例如,status_forcelist=[503] 会在状态码 503(服务不可用)时重试。

默认情况下,重试只会在以下情况下触发:

  • 无法从连接池获取连接。
  • TimeoutError
  • 抛出 HTTPException(在 Python 3 中来自 http.client,否则来自 httplib)。这通常是一些低级的 HTTP 异常,比如 URL 或协议格式不正确。
  • SocketError
  • ProtocolError

注意,这些都是阻止正常 HTTP 响应返回的异常。如果有任何正常的响应产生,就不会进行重试。如果不使用 status_forcelist,即使响应状态是 500 也不会重试。

为了让它在与远程 API 或网页服务器交互时表现得更直观,我会使用上面的代码片段,这样可以在状态为 500502503504 时强制重试,这些状态在网络上并不少见,并且在等待足够长的时间后可能会恢复。

234

实际上,重试的功能是由底层的 urllib3 库来实现的。如果你想设置一个不同的最大重试次数,可以使用 替代的传输适配器

from requests.adapters import HTTPAdapter

s = requests.Session()
s.mount('http://stackoverflow.com', HTTPAdapter(max_retries=5))

这里的 max_retries 参数可以是一个整数,或者是一个 Retry() 对象;后者可以让你更精细地控制哪些类型的失败会被重试(如果用整数值,它会变成一个只处理连接失败的 Retry() 实例;一旦连接成功后出现的错误默认是不会被处理的,因为这些错误可能会导致其他问题)。


这是一个旧的回答,早于 requests 1.2.1 的发布

requests 库其实并没有提供很好的配置选项,也不打算这样做(可以参考 这个请求)。在当前版本(requests 1.1)中,重试次数被设置为 0。如果你真的想把它设置为更高的值,就需要全局设置:

import requests

requests.adapters.DEFAULT_RETRIES = 5

这个常量没有文档说明;使用时要小心,因为未来的版本可能会改变处理方式。

更新:这确实发生了变化;在 1.2.1 版本中,添加了设置 max_retries 参数的选项,在 HTTPAdapter()中,所以现在你需要使用替代的传输适配器,见上文。猴子补丁的方法不再有效,除非你也补丁 HTTPAdapter.__init__() 的默认值(这非常不推荐)。

撰写回答