看到重试使用urllib3.PoolManager发送的请求而不重试已配置

时间:2015-01-22 21:49:29

标签: python urllib3

我有一些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秒。在这种情况下,事件的顺序如下:

  1. 从python客户端发送的一个请求
  2. 收到第一个请求
  3. 收到第二次请求
  4. 以状态200发送的第一个响应和表示成功的http实体
  5. 以状态200发送的第二个响应和指示失败的http实体
  6. Python客户端收到第二个响应
  7. 我尝试通过在服务器中睡觉来可靠地重现它(猜测可能存在导致重试的超时),但是不成功。我相信在服务器上不太可能发生重复,因为它只是一个基本的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)))
    

1 个答案:

答案 0 :(得分:1)

urllib3具有默认重试配置,相当于Retry(3)。要彻底禁用重试,您需要在构建池或发出请求时传递retries=False

这样的事情应该有用,例如:

import urllib3
http = urllib3.PoolManager(cert_reqs='CERT_NONE', retries=False)
...

默认重试设置(as defined here)绝对可以更好地记录,如果您感觉到它,我将非常感谢您的贡献。 :)