urllib3有CertificateError(f"hostname {hostname!r} doesn't match {dnsnames[0]!r}")报错是怎么回事
问题原因
urllib3出现CertificateError的原因是由于在进行HTTPS通信时,服务端返回的SSL证书中的主机名与请求的主机名不匹配。SSL证书中包含了一组域名,只有当请求的主机名与SSL证书中包含的域名匹配时,SSL连接才能建立。如果主机名与SSL证书中的域名不匹配,urllib3会抛出CertificateError异常。
解决方案
当 urllib3
出现 CertificateError(hostname doesn't match ...)
错误时,通常是因为服务器返回的SSL证书中的主机名与实际连接的主机名不匹配导致的。这可能是因为证书的 Common Name (CN) 或 Subject Alternative Name (SAN) 字段中列出的主机名与当前正在尝试连接的主机名不一致。
要解决这个问题,可以采取以下方法之一:
1. 确保主机名匹配:首先,请确保代码中的请求的主机名(hostname)与服务器SSL证书中的主机名匹配。如果是在浏览器中出现该问题,也可以尝试刷新页面或清除缓存看看是否解决了问题。
2. 忽略主机名检查:在某些情况下,您可能希望忽略主机名检查,可以通过设置 urllib3
的 PoolManager
的 assert_hostname
参数为 False
来实现。但这样可能会存在安全风险,因为SSL证书主机名验证的目的是确保连接的目标是预期的服务器,建议仅在了解风险的情况下使用此方法。
下面是一个示例代码,演示如何在 urllib3
中忽略主机名检查:
import urllib3
http = urllib3.PoolManager(assert_hostname=False)
response = http.request('GET', 'https://example.com')
print(response.data)
在实际应用中,应该谨慎使用忽略主机名检查的方法,并且最好在确认服务器证书配置正确的情况下解决证书主机名不匹配的问题。
具体例子
当urllib3
出现CertificateError
错误,提示"hostname {hostname!r} doesn't match {dnsnames[0]!r}"时,可以通过设置REQUESTS_CA_BUNDLE
环境变量来正确使用。
REQUESTS_CA_BUNDLE
环境变量用于指定自定义的CA证书文件路径,因为有时候urllib3
无法正确验证SSL证书。通过设置这个环境变量,可以强制urllib3
使用指定的CA证书文件进行验证,从而避免CertificateError错误。
下面是一个具体的例子:
import os
import requests
# 设置REQUESTS_CA_BUNDLE环境变量为自定义CA证书文件路径
os.environ['REQUESTS_CA_BUNDLE'] = '/path/to/custom/ca-bundle.crt'
url = 'https://example.com'
response = requests.get(url)
print(response.text)
在上面的例子中,我们首先将REQUESTS_CA_BUNDLE
环境变量设置为包含自定义CA证书的文件路径'/path/to/custom/ca-bundle.crt'
。然后,我们发送一个HTTPS请求给'https://example.com'
,这个请求会使用我们指定的自定义CA证书来验证SSL证书,避免了CertificateError错误的出现。