由于 pyopenssl / OpenSSL 错误,Pip 安装失败

Pip install failing due to pyopenssl / OpenSSL error

我是 运行 Python WSL2 上的 3.8.10(Windows Linux 的子系统),在公司环境中遇到以下错误,我当尝试使用 pip 安装任何东西时,相信与 pyopenssl / OpenSSL 有关。我不清楚我是否进行了导致这种奇怪行为的任何系统级更改。

urllib3.exceptions.ProtocolError: ('Connection broken: OSError("(104, \'ECONNRESET\')")', OSError("(104, 'ECONNRESET')"))

这是完整的堆栈跟踪:

$ pip install --upgrade pip

/usr/share/python-wheels/urllib3-1.25.8-py2.py3-none-any.whl/urllib3/connectionpool.py:999: InsecureRequestWarning: Unverified HTTPS request is being made to host 'pypi.org'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
/usr/share/python-wheels/urllib3-1.25.8-py2.py3-none-any.whl/urllib3/connectionpool.py:999: InsecureRequestWarning: Unverified HTTPS request is being made to host 'pypi.org'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
Collecting pip
/usr/share/python-wheels/urllib3-1.25.8-py2.py3-none-any.whl/urllib3/connectionpool.py:999: InsecureRequestWarning: Unverified HTTPS request is being made to host 'files.pythonhosted.org'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
  Downloading pip-21.3.1-py3-none-any.whl (1.7 MB)
     |███▋                            | 194 kB 54.4 MB/s eta 0:00:01ERROR: Exception:
Traceback (most recent call last):
  File "/usr/share/python-wheels/urllib3-1.25.8-py2.py3-none-any.whl/urllib3/contrib/pyopenssl.py", line 313, in recv_into
    return self.connection.recv_into(*args, **kwargs)
  File "/usr/lib/python3/dist-packages/OpenSSL/SSL.py", line 1822, in recv_into
    self._raise_ssl_error(self._ssl, result)
  File "/usr/lib/python3/dist-packages/OpenSSL/SSL.py", line 1622, in _raise_ssl_error
    raise WantReadError()
OpenSSL.SSL.WantReadError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/share/python-wheels/urllib3-1.25.8-py2.py3-none-any.whl/urllib3/contrib/pyopenssl.py", line 313, in recv_into
    return self.connection.recv_into(*args, **kwargs)
  File "/usr/lib/python3/dist-packages/OpenSSL/SSL.py", line 1822, in recv_into
    self._raise_ssl_error(self._ssl, result)
  File "/usr/lib/python3/dist-packages/OpenSSL/SSL.py", line 1639, in _raise_ssl_error
    raise SysCallError(errno, errorcode.get(errno))
OpenSSL.SSL.SysCallError: (104, 'ECONNRESET')

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/share/python-wheels/urllib3-1.25.8-py2.py3-none-any.whl/urllib3/response.py", line 425, in _error_catcher
    yield
  File "/usr/share/python-wheels/urllib3-1.25.8-py2.py3-none-any.whl/urllib3/response.py", line 507, in read
    data = self._fp.read(amt) if not fp_closed else b""
  File "/usr/lib/python3.8/http/client.py", line 459, in read
    n = self.readinto(b)
  File "/usr/lib/python3.8/http/client.py", line 503, in readinto
    n = self.fp.readinto(b)
  File "/usr/lib/python3.8/socket.py", line 669, in readinto
    return self._sock.recv_into(b)
  File "/usr/share/python-wheels/urllib3-1.25.8-py2.py3-none-any.whl/urllib3/contrib/pyopenssl.py", line 328, in recv_into
    return self.recv_into(*args, **kwargs)
  File "/usr/share/python-wheels/urllib3-1.25.8-py2.py3-none-any.whl/urllib3/contrib/pyopenssl.py", line 318, in recv_into
    raise SocketError(str(e))
OSError: (104, 'ECONNRESET')

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/pip/_internal/cli/base_command.py", line 186, in _main
    status = self.run(options, args)
  File "/usr/lib/python3/dist-packages/pip/_internal/commands/install.py", line 357, in run
    resolver.resolve(requirement_set)
  File "/usr/lib/python3/dist-packages/pip/_internal/legacy_resolve.py", line 177, in resolve
    discovered_reqs.extend(self._resolve_one(requirement_set, req))
  File "/usr/lib/python3/dist-packages/pip/_internal/legacy_resolve.py", line 333, in _resolve_one
    abstract_dist = self._get_abstract_dist_for(req_to_install)
  File "/usr/lib/python3/dist-packages/pip/_internal/legacy_resolve.py", line 282, in _get_abstract_dist_for
    abstract_dist = self.preparer.prepare_linked_requirement(req)
  File "/usr/lib/python3/dist-packages/pip/_internal/operations/prepare.py", line 480, in prepare_linked_requirement
    local_path = unpack_url(
  File "/usr/lib/python3/dist-packages/pip/_internal/operations/prepare.py", line 282, in unpack_url
    return unpack_http_url(
  File "/usr/lib/python3/dist-packages/pip/_internal/operations/prepare.py", line 158, in unpack_http_url
    from_path, content_type = _download_http_url(
  File "/usr/lib/python3/dist-packages/pip/_internal/operations/prepare.py", line 303, in _download_http_url
    for chunk in download.chunks:
  File "/usr/lib/python3/dist-packages/pip/_internal/utils/ui.py", line 160, in iter
    for x in it:
  File "/usr/lib/python3/dist-packages/pip/_internal/network/utils.py", line 15, in response_chunks
    for chunk in response.raw.stream(
  File "/usr/share/python-wheels/urllib3-1.25.8-py2.py3-none-any.whl/urllib3/response.py", line 564, in stream
    data = self.read(amt=amt, decode_content=decode_content)
  File "/usr/share/python-wheels/urllib3-1.25.8-py2.py3-none-any.whl/urllib3/response.py", line 529, in read
    raise IncompleteRead(self._fp_bytes_read, self.length_remaining)
  File "/usr/lib/python3.8/contextlib.py", line 131, in __exit__
    self.gen.throw(type, value, traceback)
  File "/usr/share/python-wheels/urllib3-1.25.8-py2.py3-none-any.whl/urllib3/response.py", line 443, in _error_catcher
    raise ProtocolError("Connection broken: %r" % e, e)
urllib3.exceptions.ProtocolError: ('Connection broken: OSError("(104, \'ECONNRESET\')")', OSError("(104, 'ECONNRESET')"))

更新:有趣的是,如果我省略了 --upgrade 参数,我会得到一条略有不同的错误消息,它可能更有帮助,即 too many 503 error responses.

$ pip install jellyfish

Collecting jellyfish
ERROR: Could not install packages due to an EnvironmentError: HTTPSConnectionPool(host='files.pythonhosted.org', port=443): Max retries exceeded with url: /packages/88/ee/c8c7a899960e3a116c0e0cc95aa250fb7269784a472fa590b5ce042cc48a/jellyfish-0.8.9.tar.gz (Caused by ResponseError('too many 503 error responses'))

我可以 ping files.pythonhosted.orgpypi.org 都没有问题,但是我不能 wgetcurl.

这是 curl 的输出(编辑了一些信息)。

$curl -v https://files.pythonhosted.org/packages/88/ee/c8c7a899960e3a116c0e0cc95aa250fb7269784a472fa590b5ce042cc48a/jellyfish-0.8.9.tar.gz

*   Trying 151.101.129.63:443...
* TCP_NODELAY set
* Connected to files.pythonhosted.org (151.101.129.63) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN, server accepted to use h2
* Server certificate:
*  subject: CN=*.pythonhosted.org
*  start date: Dec 24 19:42:31 2021 GMT
*  expire date: Jan 25 19:42:30 2023 GMT
*  subjectAltName: host "files.pythonhosted.org" matched cert's "*.pythonhosted.org"
*  issuer: CN=<redacted company cert>
*  SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x5594a1ea0860)
> GET /packages/88/ee/c8c7a899960e3a116c0e0cc95aa250fb7269784a472fa590b5ce042cc48a/jellyfish-0.8.9.tar.gz HTTP/2
> Host: files.pythonhosted.org
> user-agent: curl/7.68.0
> accept: */*
>
* Connection state changed (MAX_CONCURRENT_STREAMS == 4294967295)!
* Connection state changed (MAX_CONCURRENT_STREAMS == 100)!
< HTTP/2 200
< last-modified: Tue, 26 Oct 2021 15:23:22 GMT
< etag: "8ffa7a9bdb4b7c2746277467ea321ea7"
< content-type: application/x-tar
< x-goog-hash: crc32c=iBiiWQ==
< x-goog-hash: md5=j/p6m9tLfCdGJ3Rn6jIepw==
< server: UploadServer
< cache-control: max-age=365000000, immutable, public
< accept-ranges: bytes
< date: Fri, 07 Jan 2022 17:01:32 GMT
< age: 3218451
< x-served-by: cache-sea4472-SEA, cache-lga21959-LGA
< x-cache: HIT, HIT
< x-cache-hits: 1, 1
< x-timer: S1641574892.134802,VS0,VE1
< strict-transport-security: max-age=31536000; includeSubDomains; preload
< x-frame-options: deny
< x-xss-protection: 1; mode=block
< x-content-type-options: nosniff
< x-robots-header: noindex
< access-control-allow-methods: GET, OPTIONS
< access-control-allow-headers: Range
< access-control-allow-origin: *
< content-length: 137296
<
* transfer closed with 137296 bytes remaining to read
* stopped the pause stream!
* Connection #0 to host files.pythonhosted.org left intact
curl: (18) transfer closed with 137296 bytes remaining to read

根据评论,我们最终确定 pip 下载被公司政策阻止。

帮助我们找到正确解决方案的故障排除步骤:

  • A ping files.pythonhosted.org 成功了,所以我们接下来尝试...

  • 手动下载 original/updated 问题 pip 错误报告的 URI:

    pip install jellyfish
    
    Collecting jellyfish
    ERROR: Could not install packages due to an EnvironmentError: HTTPSConnectionPool(host='files.pythonhosted.org', port=443): Max retries exceeded with url: /packages/88/ee/c8c7a899960e3a116c0e0cc95aa250fb7269784a472fa590b5ce042cc48a/jellyfish-0.8.9.tar.gz (Caused by ResponseError('too many 503 error responses'))    
    
    wget https://files.pythonhosted.org/packages/88/ee/c8c7a899960e3a116c0e0cc95aa250fb7269784a472fa590b5ce042cc48a/jellyfish-0.8.9.tar.gz
    

    这也失败了 503。

  • 因此,为了确定问题是出在 WSL 实例本身还是堆栈更高的地方,我们开始尝试从 PowerShell 下载相同的文件:

    Invoke-WebRequest -Uri "https://files.pythonhosted.org/packages/88/ee/c8c7a899960e3a116c0e0cc95aa250fb7269784a472fa590b5ce042cc48a/jellyfish-0.8.9.tar.gz" -OutFile jellyfish-0.8.9.tar.gz
    

    这导致了一条(最终)信息性消息:

    Invoke-WebRequest : File Transfer Blocked Transfer of the file you were trying to download or upload has been blocked in accordance with company policy. Please contact your system administrator if you believe this is in error.
    

将这些旧的故障排除步骤留在此处以防它们对任何人有所帮助,但请注意它们解决这个特定问题没有用处:

  • 首先,只是一个健全性检查,但是 sudo apt update && sudo apt upgrade 以确保没有一些您尚未加载的证书更新,但我假设您已经完成已经。

  • 其次,我真的不希望这里的结果有任何不同,但是尝试创建一个 venv 有意义吗?

    sudo apt install python3-venv
    python -m venv dirname
    source dirname/bin/activate
    

    然后在 venv 中尝试 pip?

  • 下一步,绝对不推荐,但是按照堆栈跟踪中的 link 将带您到 urllib3 Certificate Verification page

    这似乎表明您可以尝试 cert_reqs = "CERT_NONE" pip install --upgrade pip

    虽然关闭证书检查可能有点可怕。我可能会在“备份”的 WSL 实例中尝试这个。如果您需要有关如何操作的说明,请告诉我。

试试这个:

python -m pip install --trusted-host pypi.org --trusted-host pypi.python.org --trusted-host files.pythonhosted.org <package name>