无法使用 try except 捕获 requests.exceptions.ConnectionError

Til*_*man 6 python python-3.x try-except python-requests

感觉我正在慢慢失去理智。我无法捕获 REST-API 请求中的连接错误。我在 stackoverflow 上阅读了至少 20 个类似的问题,尝试了我能想到的所有可能的 except 语句,并尽可能简化了代码以排除某些其他库。

我正在使用 Python 3.7 和请求 2.25.1。这是对我自己的服务器上的 API 的非常基本的调用,有时会失败,但只是偶尔失败一次:

try:
    response = requests.get(url, headers=api_headers, auth=HTTPBasicAuth(username, password))
except requests.exceptions.ConnectionError:
     print("Connection error!")
     
Run Code Online (Sandbox Code Playgroud)

很抱歉,我无法提供完整的工作示例,因为我没有连接到可公开访问的 API,因此我必须删除 url、用户名和密码。

即使我尝试捕获连接错误,脚本也会失败并显示以下回溯:

Traceback (most recent call last):
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\site-packages\urllib3\connectionpool.py", line 706, in urlopen
    chunked=chunked,
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\site-packages\urllib3\connectionpool.py", line 382, in _make_request
    self._validate_conn(conn)
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\site-packages\urllib3\connectionpool.py", line 1010, in _validate_conn
    conn.connect()
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\site-packages\urllib3\connection.py", line 421, in connect
    tls_in_tls=tls_in_tls,
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\site-packages\urllib3\util\ssl_.py", line 429, in ssl_wrap_socket
    sock, context, tls_in_tls, server_hostname=server_hostname
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\site-packages\urllib3\util\ssl_.py", line 472, in _ssl_wrap_socket_impl
    return ssl_context.wrap_socket(sock, server_hostname=server_hostname)
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\ssl.py", line 412, in wrap_socket
    session=session
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\ssl.py", line 850, in _create
    self.do_handshake()
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\ssl.py", line 1108, in do_handshake
    self._sslobj.do_handshake()
TimeoutError: [WinError 10060] Ein Verbindungsversuch ist fehlgeschlagen, da die Gegenstelle nach einer bestimmten Zeitspanne nicht richtig reagiert hat, oder die hergestellte Verbindung war fehlerhaft, da der verbundene Host nicht reagiert hat

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\site-packages\requests\adapters.py", line 449, in send
    timeout=timeout
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\site-packages\urllib3\connectionpool.py", line 756, in urlopen
    method, url, error=e, _pool=self, _stacktrace=sys.exc_info()[2]
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\site-packages\urllib3\util\retry.py", line 532, in increment
    raise six.reraise(type(error), error, _stacktrace)
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\site-packages\urllib3\packages\six.py", line 734, in reraise
    raise value.with_traceback(tb)
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\site-packages\urllib3\connectionpool.py", line 706, in urlopen
    chunked=chunked,
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\site-packages\urllib3\connectionpool.py", line 382, in _make_request
    self._validate_conn(conn)
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\site-packages\urllib3\connectionpool.py", line 1010, in _validate_conn
    conn.connect()
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\site-packages\urllib3\connection.py", line 421, in connect
    tls_in_tls=tls_in_tls,
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\site-packages\urllib3\util\ssl_.py", line 429, in ssl_wrap_socket
    sock, context, tls_in_tls, server_hostname=server_hostname
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\site-packages\urllib3\util\ssl_.py", line 472, in _ssl_wrap_socket_impl
    return ssl_context.wrap_socket(sock, server_hostname=server_hostname)
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\ssl.py", line 412, in wrap_socket
    session=session
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\ssl.py", line 850, in _create
    self.do_handshake()
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\ssl.py", line 1108, in do_handshake
    self._sslobj.do_handshake()
urllib3.exceptions.ProtocolError: ('Connection aborted.', TimeoutError(10060, 'Ein Verbindungsversuch ist fehlgeschlagen, da die Gegenstelle nach einer bestimmten Zeitspanne nicht richtig reagiert hat, oder die hergestellte Verbindung war fehlerhaft, da der verbundene Host nicht reagiert hat', None, 10060, None))

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\site-packages\requests\api.py", line 61, in request
    return session.request(method=method, url=url, **kwargs)
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\site-packages\requests\sessions.py", line 542, in request
    resp = self.send(prep, **send_kwargs)
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\site-packages\requests\sessions.py", line 655, in send
    r = adapter.send(request, **kwargs)
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\site-packages\requests\adapters.py", line 498, in send
    raise ConnectionError(err, request=request)
requests.exceptions.ConnectionError: ('Connection aborted.', TimeoutError(10060, 'Ein Verbindungsversuch ist fehlgeschlagen, da die Gegenstelle nach einer bestimmten Zeitspanne nicht richtig reagiert hat, oder die hergestellte Verbindung war fehlerhaft, da der verbundene Host nicht reagiert hat', None, 10060, None))

Run Code Online (Sandbox Code Playgroud)

我不明白如果我捕获到该错误,脚本怎么可能因 requests.exceptions.ConnectionError 而失败?

如果我正确理解了回溯,则错误不会在我的代码中抛出,因此我无法捕获它?我所看到的只是像 ssl.py 和 urllib 和 request 这样的 python 库,但不是我的代码中的一行。那么我该如何捕捉呢?

非常感谢任何帮助!

编辑(因为这在评论中是不可能的)。@Thomas 做了一个有用的评论,连接到 httpstat.us:81 进行调试。所以我尝试用 替换我的order_response = requests.get()电话response = requests.get("http://httpstat.us:81")。这是我的代码中的确切块:

try:
    order_response = requests.get(order_access_url, headers=api_headers, auth=HTTPBasicAuth(username, password))
    if order_response.status_code == 200:
        order_content = json.loads(order_response.text)
    else:
        order_content = ""
except requests.exceptions.ConnectionError:
    print("Connection error!")
Run Code Online (Sandbox Code Playgroud)

如果我尝试连接到http://httpstat.us:81它实际上会捕获错误。如果我故意不抓住它,错误看起来像这样:

Traceback (most recent call last):
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\site-packages\urllib3\connection.py", line 170, in _new_conn
    (self._dns_host, self.port), self.timeout, **extra_kw
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\site-packages\urllib3\util\connection.py", line 96, in create_connection
    raise err
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\site-packages\urllib3\util\connection.py", line 86, in create_connection
    sock.connect(sa)
TimeoutError: [WinError 10060] Ein Verbindungsversuch ist fehlgeschlagen, da die Gegenstelle nach einer bestimmten Zeitspanne nicht richtig reagiert hat, oder die hergestellte Verbindung war fehlerhaft, da der verbundene Host nicht reagiert hat

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\site-packages\urllib3\connectionpool.py", line 706, in urlopen
    chunked=chunked,
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\site-packages\urllib3\connectionpool.py", line 394, in _make_request
    conn.request(method, url, **httplib_request_kw)
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\site-packages\urllib3\connection.py", line 234, in request
    super(HTTPConnection, self).request(method, url, body=body, headers=headers)
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\http\client.py", line 1229, in request
    self._send_request(method, url, body, headers, encode_chunked)
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\http\client.py", line 1275, in _send_request
    self.endheaders(body, encode_chunked=encode_chunked)
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\http\client.py", line 1224, in endheaders
    self._send_output(message_body, encode_chunked=encode_chunked)
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\http\client.py", line 1016, in _send_output
    self.send(msg)
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\http\client.py", line 956, in send
    self.connect()
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\site-packages\urllib3\connection.py", line 200, in connect
    conn = self._new_conn()
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\site-packages\urllib3\connection.py", line 182, in _new_conn
    self, "Failed to establish a new connection: %s" % e
urllib3.exceptions.NewConnectionError: <urllib3.connection.HTTPConnection object at 0x00000223F9B42860>: Failed to establish a new connection: [WinError 10060] Ein Verbindungsversuch ist fehlgeschlagen, da die Gegenstelle nach einer bestimmten Zeitspanne nicht richtig reagiert hat, oder die hergestellte Verbindung war fehlerhaft, da der verbundene Host nicht reagiert hat

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\site-packages\requests\adapters.py", line 449, in send
    timeout=timeout
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\site-packages\urllib3\connectionpool.py", line 756, in urlopen
    method, url, error=e, _pool=self, _stacktrace=sys.exc_info()[2]
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\site-packages\urllib3\util\retry.py", line 574, in increment
    raise MaxRetryError(_pool, url, error or ResponseError(cause))
urllib3.exceptions.MaxRetryError: HTTPConnectionPool(host='httpstat.us', port=81): Max retries exceeded with url: / (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x00000223F9B42860>: Failed to establish a new connection: [WinError 10060] Ein Verbindungsversuch ist fehlgeschlagen, da die Gegenstelle nach einer bestimmten Zeitspanne nicht richtig reagiert hat, oder die hergestellte Verbindung war fehlerhaft, da der verbundene Host nicht reagiert hat'))

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Daten\cloud.bss-archery.com\BSS\_Twain\modules\order_extracts_api.py", line 50, in create_order_analysis
    response = requests.get("http://httpstat.us:81")
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\site-packages\requests\api.py", line 76, in get
    return request('get', url, params=params, **kwargs)
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\site-packages\requests\api.py", line 61, in request
    return session.request(method=method, url=url, **kwargs)
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\site-packages\requests\sessions.py", line 542, in request
    resp = self.send(prep, **send_kwargs)
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\site-packages\requests\sessions.py", line 655, in send
    r = adapter.send(request, **kwargs)
  File "C:\Users\Tilman\AppData\Local\Programs\Python\Python37\lib\site-packages\requests\adapters.py", line 516, in send
    raise ConnectionError(e, request=request)
requests.exceptions.ConnectionError: HTTPConnectionPool(host='httpstat.us', port=81): Max retries exceeded with url: / (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x00000223F9B42860>: Failed to establish a new connection: [WinError 10060] Ein Verbindungsversuch ist fehlgeschlagen, da die Gegenstelle nach einer bestimmten Zeitspanne nicht richtig reagiert hat, oder die hergestellte Verbindung war fehlerhaft, da der verbundene Host nicht reagiert hat'))
Run Code Online (Sandbox Code Playgroud)

所以我仍然很困惑,因为回溯中的最后一个条目实际上是相同的,requests.exceptions.ConnectionError但它没有被我的现实世界应用程序捕获。然而,它是由另一行提出的\lib\site-packages\requests\adapters.py

Til*_*man 4

好吧,我可以自己解决。有点儿。

一个巨大的问题是回溯没有指向引发异常的代码行。我仍然不知道为什么会这样,以及这是否应该被视为请求中的错误。但无论如何:请求在adapters.py中引发ConnectionError,但起源是协议或套接字错误。这是adapters.py 中的第 497 行:

except (ProtocolError, socket.error) as err:
    raise ConnectionError(err, request=request)
Run Code Online (Sandbox Code Playgroud)

回溯TimeoutError: [WinError 10060]中的实际上指向套接字错误。

来自https://hstechdocs.helpsystems.com/manuals/globalscape/archive/cuteftp8/Socket_errors_10060_10061_10064_10065.htm

10060 范围内的套接字错误是 Winsock 错误。一般是由于出站连接问题或主机端连接问题引起的。

这就是为什么我无法使用 httpstat.us 重现该错误。

解决方案是将其捕获为 OSError:

try:
    response = requests.get(url, headers=api_headers, auth=HTTPBasicAuth(username, password))
except OSError as e:
     print(e)
Run Code Online (Sandbox Code Playgroud)

说实话,这有点令人沮丧,因为我仍然不知道为什么请求中引发 ConnectionError 的 ProtocolError 或 socket.error 需要用“OSError”捕获,但在这一点上,我很高兴我能找到任何解决方案。