查看使用 urllib3.PoolManager 发送的请求的重试,但未配置重试
Seeing retry of a request sent using urllib3.PoolManager without retries configured
我有一些 python 代码如下所示:
import urllib3
http = urllib3.PoolManager(cert_reqs='CERT_NONE')
...
full_url = 'https://[%s]:%d%s%s' % \
(address, port, base_uri, relative_uri)
kwargs = {
'headers': {
'Host': '%s:%d' % (hostname, port)
}
}
if data is not None:
kwargs['body'] = json.dumps(data, indent=2, sort_keys=True)
# Directly use request_encode_url instead of request because requests
# will try to encode the body as 'multipart/form-data'.
response = http.request_encode_url('POST', full_url, **kwargs)
log.debug('Received response: HTTP status %d. Body: %s' %
(response.status, repr(response.data)))
我有一个日志行在发出请求的代码之前打印一次,log.debug('Received...')
行打印一次。但是,在服务器端,我偶尔会看到两个请求(它们都是此代码块发送的相同 POST 请求),间隔大约 1-5 秒。在这种情况下,事件的顺序如下:
- 从 python 客户端发送一个请求
- 收到第一个请求
- 收到第二个请求
- 发送的第一个响应带有状态 200 和一个指示成功的 http 实体
- 发送的第二个响应带有状态 200 和指示失败的 http 实体
- Python客户端收到第二次响应
我试图通过在服务器休眠来可靠地重现它(猜测可能是超时导致重试),但没有成功。我相信服务器上不太可能发生重复,因为它只是一个基本的 Scala Spray 服务器,并且没有在其他客户端上看到过这种情况。查看 PoolManager
的源代码,我找不到任何包含重试的地方。有一个用可选参数指定的重试机制,但上面的代码中没有使用这个可选参数。
有人知道这个额外的请求可能来自哪里吗?
编辑:@shazow 给出了一个关于 retries
的指针,默认值为 3,但我按照建议更改了代码并收到以下错误:
Traceback (most recent call last):
File "my_file.py", line 23, in <module>
response = http.request_encode_url('GET', full_url, **kwargs)
File "/usr/lib/python2.7/dist-packages/urllib3/request.py", line 88, in request_encode_url
return self.urlopen(method, url, **urlopen_kw)
File "/usr/lib/python2.7/dist-packages/urllib3/poolmanager.py", line 145, in urlopen
conn = self.connection_from_host(u.host, port=u.port, scheme=u.scheme)
File "/usr/lib/python2.7/dist-packages/urllib3/poolmanager.py", line 119, in connection_from_host
pool = self._new_pool(scheme, host, port)
File "/usr/lib/python2.7/dist-packages/urllib3/poolmanager.py", line 86, in _new_pool
return pool_cls(host, port, **kwargs)
TypeError: __init__() got an unexpected keyword argument 'retries'`
编辑 #2:对 kwargs
的以下更改似乎对我有用:
import urllib3
http = urllib3.PoolManager(cert_reqs='CERT_NONE')
...
full_url = 'https://[%s]:%d%s%s' % \
(address, port, base_uri, relative_uri)
kwargs = {
'headers': {
'Host': '%s:%d' % (hostname, port)
},
'retries': 0
}
if data is not None:
kwargs['body'] = json.dumps(data, indent=2, sort_keys=True)
# Directly use request_encode_url instead of request because requests
# will try to encode the body as 'multipart/form-data'.
response = http.request_encode_url('POST', full_url, **kwargs)
log.debug('Received response: HTTP status %d. Body: %s' %
(response.status, repr(response.data)))
urllib3 有一个默认的重试配置,相当于Retry(3)
。要完全禁用重试,您需要在构建池或发出请求时传递 retries=False
。
像这样的东西应该可以工作,例如:
import urllib3
http = urllib3.PoolManager(cert_reqs='CERT_NONE', retries=False)
...
默认重试设置 (as defined here) 绝对可以更好地记录,如果您愿意,我将不胜感激。 :)
我有一些 python 代码如下所示:
import urllib3
http = urllib3.PoolManager(cert_reqs='CERT_NONE')
...
full_url = 'https://[%s]:%d%s%s' % \
(address, port, base_uri, relative_uri)
kwargs = {
'headers': {
'Host': '%s:%d' % (hostname, port)
}
}
if data is not None:
kwargs['body'] = json.dumps(data, indent=2, sort_keys=True)
# Directly use request_encode_url instead of request because requests
# will try to encode the body as 'multipart/form-data'.
response = http.request_encode_url('POST', full_url, **kwargs)
log.debug('Received response: HTTP status %d. Body: %s' %
(response.status, repr(response.data)))
我有一个日志行在发出请求的代码之前打印一次,log.debug('Received...')
行打印一次。但是,在服务器端,我偶尔会看到两个请求(它们都是此代码块发送的相同 POST 请求),间隔大约 1-5 秒。在这种情况下,事件的顺序如下:
- 从 python 客户端发送一个请求
- 收到第一个请求
- 收到第二个请求
- 发送的第一个响应带有状态 200 和一个指示成功的 http 实体
- 发送的第二个响应带有状态 200 和指示失败的 http 实体
- Python客户端收到第二次响应
我试图通过在服务器休眠来可靠地重现它(猜测可能是超时导致重试),但没有成功。我相信服务器上不太可能发生重复,因为它只是一个基本的 Scala Spray 服务器,并且没有在其他客户端上看到过这种情况。查看 PoolManager
的源代码,我找不到任何包含重试的地方。有一个用可选参数指定的重试机制,但上面的代码中没有使用这个可选参数。
有人知道这个额外的请求可能来自哪里吗?
编辑:@shazow 给出了一个关于 retries
的指针,默认值为 3,但我按照建议更改了代码并收到以下错误:
Traceback (most recent call last):
File "my_file.py", line 23, in <module>
response = http.request_encode_url('GET', full_url, **kwargs)
File "/usr/lib/python2.7/dist-packages/urllib3/request.py", line 88, in request_encode_url
return self.urlopen(method, url, **urlopen_kw)
File "/usr/lib/python2.7/dist-packages/urllib3/poolmanager.py", line 145, in urlopen
conn = self.connection_from_host(u.host, port=u.port, scheme=u.scheme)
File "/usr/lib/python2.7/dist-packages/urllib3/poolmanager.py", line 119, in connection_from_host
pool = self._new_pool(scheme, host, port)
File "/usr/lib/python2.7/dist-packages/urllib3/poolmanager.py", line 86, in _new_pool
return pool_cls(host, port, **kwargs)
TypeError: __init__() got an unexpected keyword argument 'retries'`
编辑 #2:对 kwargs
的以下更改似乎对我有用:
import urllib3
http = urllib3.PoolManager(cert_reqs='CERT_NONE')
...
full_url = 'https://[%s]:%d%s%s' % \
(address, port, base_uri, relative_uri)
kwargs = {
'headers': {
'Host': '%s:%d' % (hostname, port)
},
'retries': 0
}
if data is not None:
kwargs['body'] = json.dumps(data, indent=2, sort_keys=True)
# Directly use request_encode_url instead of request because requests
# will try to encode the body as 'multipart/form-data'.
response = http.request_encode_url('POST', full_url, **kwargs)
log.debug('Received response: HTTP status %d. Body: %s' %
(response.status, repr(response.data)))
urllib3 有一个默认的重试配置,相当于Retry(3)
。要完全禁用重试,您需要在构建池或发出请求时传递 retries=False
。
像这样的东西应该可以工作,例如:
import urllib3
http = urllib3.PoolManager(cert_reqs='CERT_NONE', retries=False)
...
默认重试设置 (as defined here) 绝对可以更好地记录,如果您愿意,我将不胜感激。 :)