Python 请求:如何确定 MaxRetries 异常的响应代码

Gil*_*nap 5 python python-requests

当我的 get 或 post 出现错误响应直到超过最大重试次数时,我想知道问题的原因。

我在下面有一个示例测试。这会按预期抛出 MaxRetriesError。然而,原来的HTTPError似乎丢失了。

from requests import Session, exceptions
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
from unittest import TestCase
import logging


class TestRequests(TestCase):

    def test_retries(self):
        session = Session()
        retries = Retry(total=5,
                        backoff_factor=0.1,
                        status_forcelist=[500, 502, 503, 504],
                        method_whitelist=frozenset(['GET', 'POST']))

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

        try:
            result = session.get('https://httpbin.org/status/500',
                                 stream=True,
                                 timeout=2)
            print(result)
        except exceptions.HTTPError as e:
            logging.error('http', exc_info=e)
        except exceptions.RetryError as e:
            logging.error('retry', exc_info=e)
Run Code Online (Sandbox Code Playgroud)

Traceback 显示以下信息,它仅追溯到最后一个 RetryError,而不是 HTTPError。异常的字符串确实提到了响应代码,但解析错误消息字符串并不是一种可靠的方法。

ERROR:root:retry
Traceback (most recent call last):
  File "/home/giles/venv/gphotos-sync3/lib/python3.6/site-packages/requests/adapters.py", line 449, in send
    timeout=timeout
  File "/home/giles/venv/gphotos-sync3/lib/python3.6/site-packages/urllib3/connectionpool.py", line 731, in urlopen
    body_pos=body_pos, **response_kw)
  File "/home/giles/venv/gphotos-sync3/lib/python3.6/site-packages/urllib3/connectionpool.py", line 731, in urlopen
    body_pos=body_pos, **response_kw)
  File "/home/giles/venv/gphotos-sync3/lib/python3.6/site-packages/urllib3/connectionpool.py", line 731, in urlopen
    body_pos=body_pos, **response_kw)
  [Previous line repeated 2 more times]
  File "/home/giles/venv/gphotos-sync3/lib/python3.6/site-packages/urllib3/connectionpool.py", line 711, in urlopen
    retries = retries.increment(method, url, response=response, _pool=self)
  File "/home/giles/venv/gphotos-sync3/lib/python3.6/site-packages/urllib3/util/retry.py", line 398, in increment
    raise MaxRetryError(_pool, url, error or ResponseError(cause))
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='httpbin.org', port=443): Max retries exceeded with url: /status/500 (Caused by ResponseError('too many 500 error responses',))

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/giles/github/gphotos-sync/test/test_requests.py", line 36, in test_retries
    timeout=2)
  File "/home/giles/venv/gphotos-sync3/lib/python3.6/site-packages/requests/sessions.py", line 546, in get
    return self.request('GET', url, **kwargs)
  File "/home/giles/venv/gphotos-sync3/lib/python3.6/site-packages/requests/sessions.py", line 533, in request
    resp = self.send(prep, **send_kwargs)
  File "/home/giles/venv/gphotos-sync3/lib/python3.6/site-packages/requests/sessions.py", line 646, in send
    r = adapter.send(request, **kwargs)
  File "/home/giles/venv/gphotos-sync3/lib/python3.6/site-packages/requests/adapters.py", line 507, in send
    raise RetryError(e, request=request)
requests.exceptions.RetryError: HTTPSConnectionPool(host='httpbin.org', port=443): Max retries exceeded with url: /status/500 (Caused by ResponseError('too many 500 error responses',))


Ran 1 test in 4.092s

OK
Run Code Online (Sandbox Code Playgroud)

Gil*_*nap 5

我发现如果我告诉 Retries 不要引发自己的错误 (raise_on_status=False),我可以看到原始错误,但随后检查最后一个响应。请参阅下面修改后的代码。

from requests import Session, exceptions
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
from urllib3.exceptions import MaxRetryError
from unittest import TestCase
import logging


class TestRequests(TestCase):

    def test_retries(self):
        session = Session()
        retries = Retry(total=5,
                        backoff_factor=0.1,
                        status_forcelist=[500, 502, 503, 504],
                        method_whitelist=frozenset(['GET', 'POST']),
                        raise_on_status=False)

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

        try:
            result = session.get('https://httpbin.org/status/500',
                                 stream=True,
                                 timeout=2)
            print(result)
            result.raise_for_status()

        except exceptions.HTTPError as e:
            logging.error('http', exc_info=e)
        except MaxRetryError as e:
            logging.error('retry', exc_info=e)
Run Code Online (Sandbox Code Playgroud)

这导致:

------------------------------------------------------------- Captured stdout call --------------------------------------------------------------
<Response [500]>
--------------------------------------------------------------- Captured log call ---------------------------------------------------------------
test-requests.py            30 ERROR    http
Traceback (most recent call last):
  File "/home/hgv27681/github/tests/test-requests.py", line 27, in test_retries
    result.raise_for_status()
  File "/home/hgv27681/github/venv3/lib/python3.6/site-packages/requests/models.py", line 940, in raise_for_status
    raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 500 Server Error: INTERNAL SERVER ERROR for url: https://httpbin.org/status/500
Run Code Online (Sandbox Code Playgroud)