Sor*_*shA 12 python urllib3 python-requests
考虑使用 OAuth 令牌的 http 请求。访问令牌需要作为不记名包含在标头中。但是,如果令牌已过期,则需要再次请求刷新令牌,然后重试。所以自定义重试对象将如下所示:
s = requests.Session()
### token is added to the header here
s.headers.update(token_header)
retry = OAuthRetry(
total=2,
read=2,
connect=2,
backoff_factor=1,
status_forcelist=[401],
method_whitelist=frozenset(['GET', 'POST']),
session=s
)
adapter = HTTPAdapter(max_retries=retry)
s.mount('http://', adapter)
s.mount('https://', adapter)
r = s.post(url, data=data)
Run Code Online (Sandbox Code Playgroud)
重试类:
class OAuthRetry(Retry):
def increment(self, method, url, *args, **kwargs):
# refresh the token here. This could be by getting a reference to the session or any other way.
return super(OAuthRetry, self).increment(method, url, *args, **kwargs)
Run Code Online (Sandbox Code Playgroud)
问题是刷新token后,HTTPConnectionPool在调用increment后仍然使用相同的header来发起请求。请参阅:https : //github.com/urllib3/urllib3/blob/master/src/urllib3/connectionpool.py#L787。尽管池的实例以增量方式传递,但更改那里的标头不会影响调用,因为它使用标头的本地副本。
这似乎是一个用例,应该经常出现请求参数在重试之间更改。
有没有办法在两次后续重试之间更改请求标头?
不,在当前版本的 Requests(2.18.4) 和 urllib3(1.22) 中。
\nopenurl重试最终由urllib3处理。并且通过跟踪整个函数的代码,重试之间没有接口可以更改headers。
并且动态改变headers不应该被视为解决方案。来自文档:
\n\nheaders \xe2\x80\x93 要发送的自定义标头的字典,例如 User-Agent、If-None-Match 等。如果 None,则使用池标头。如果提供,这些标头将完全替换任何特定于池的标头。
\n
headers是传递给函数的参数。并且不保证通过后不会被复制。尽管在当前版本的 urllib3 中,openurl不复制headers,但任何基于更改的解决方案都headers被认为是hacky,因为它基于实现而不是文档。
中断一个函数并编辑它正在使用的一些版本是非常危险的。
\n一种简单的解决方案是检查响应状态并在需要时重试,而不是向 urllib3 中注入某些内容。
\nr = s.post(url, data=data)\nif r.status_code == 401:\n # refresh the token here.\n r = s.post(url, data=data)\nRun Code Online (Sandbox Code Playgroud)\nprepare_headers请求在将标头发送到 urllib3 之前复制标头。因此 urllib3 在重试时使用编辑之前创建的副本。