Python 3.x 异步aiohttp请求失败,但同步请求成功

Python 3.x 异步aiohttp请求失败,但同步请求成功,python-3.x,asynchronous,python-asyncio,aiohttp,Python 3.x,Asynchronous,Python Asyncio,Aiohttp,使用以下代码,当我使用异步aiohttp时,我得到无法连接到主机…:443 ssl:True。当我使用同步请求时,它会成功 whitehouse.gov链接失败,但是google.com在异步和同步情况下都成功 出什么事了?这与FreeBSD8上的python 3.4.2、aiohttp 0.14.4和2.5.3是一致的 import asyncio import aiohttp import requests urls = [ 'http://www.whitehouse.gov/c

使用以下代码,当我使用异步
aiohttp
时,我得到
无法连接到主机…:443 ssl:True
。当我使用同步
请求时,它会成功

whitehouse.gov
链接失败,但是
google.com
在异步和同步情况下都成功

出什么事了?这与FreeBSD8上的python 3.4.2、aiohttp 0.14.4和2.5.3是一致的

import asyncio
import aiohttp
import requests

urls = [
    'http://www.whitehouse.gov/cea/', 
    'http://www.whitehouse.gov/omb', 
    'http://www.google.com']


def test_sync():
    for url in urls:
        r = requests.get(url)
        print(r.status_code)


def test_async():
    for url in urls:
        try:
            r = yield from aiohttp.request('get', url)
        except aiohttp.errors.ClientOSError as e:
            print('bad eternal link %s: %s' % (url, e))
        else:
            print(r.status)


if __name__ == '__main__':
    print('async')
    asyncio.get_event_loop().run_until_complete(test_async())
    print('sync')
    test_sync()
此操作的输出为:

async
bad eternal link http://www.whitehouse.gov/cea: Cannot connect to host www.whitehouse.gov:443 ssl:True
bad eternal link http://www.whitehouse.gov/omb: Cannot connect to host www.whitehouse.gov:443 ssl:True
200
sync
200
200
200

我怀疑您的机器上的证书验证链已断开。 正如@dano所提到的,在Ubuntu上一切都正常

无论如何,您可以通过创建自定义
连接器
实例来禁用ssl验证:

import asyncio
import aiohttp

urls = [
    'http://www.whitehouse.gov/cea/',
    'http://www.whitehouse.gov/omb',
    'http://www.google.com']


def test_async():
    connector = aiohttp.TCPConnector(verify_ssl=False)
    for url in urls:
        try:
            r = yield from aiohttp.request('get', url, connector=connector)
        except aiohttp.errors.ClientOSError as e:
            print('bad eternal link %s: %s' % (url, e))
        else:
            print(r.status)


if __name__ == '__main__':
    print('async')
    asyncio.get_event_loop().run_until_complete(test_async())
顺便说一句,
请求
库附带有自己的证书包。也许我们也需要为aiohttp做同样的事情


UPD。另请参见

不要使用此Answare,因为它可能等同于禁用证书检查。

正如Le Hibou在评论中指出的,
ssl.Purpose.CLIENT\u AUTH
用于在服务器端验证客户端

此值表示上下文可用于验证Web客户端(因此,它将用于创建服务器端套接字)

查看
create\u default\u context()
的代码可以看出,在这种情况下,证书检查可能被禁用,或者至少是可选的


我收到了相同的错误消息(在Windows上),并通过以下方法解决了此问题:

导入aiohttp
导入ssl
client=aiohttp.ClientSession()
client.post(
'https://some.foo/bar/',
json={“foo”:“bar},
ssl=ssl.create\u default\u context(purpose=ssl.purpose.CLIENT\u AUTH))
这是使用的
ssl
参数设置与默认ssl上下文不同的ssl上下文。默认值为

问题在于
ssl.create\u default\u context()
的默认值是:

ssl.create\u default\u context(purpose=purpose.SERVER\u AUTH,cafile=None,capath=None,cadata=None)

在客户端验证服务器证书时,
Purpose.SERVER\u AUTH
似乎不起作用。作为客户端进行验证时,请改用
Purpose.CLIENT\u AUTH

我在一台旧Linux服务器上遇到了同样的问题,该服务器上的CA根证书已过期,在
SSLContext
中加载CA证书捆绑包修复了该问题

导入aiohttp
导入ssl
进口证书
ssl\u context=ssl.create\u default\u context(cafile=certifi.where())
与aiohttp.ClientSession()作为会话异步:
与session.get()异步https://some.foo/bar/,ssl=ssl_上下文)作为响应:
打印(等待响应。text())
这对我很有用:

if sys.version_info[0] == 3 and sys.version_info[1] >= 8 and sys.platform.startswith('win'):
    asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())

这不会在Ubuntu机器上为我复制,因为它的价值。正是问题所在,谢谢。如果我没有巧妙地隐藏在try/except后面,我会得到更多有用的信息:ssl.SSLError:[ssl:CERTIFICATE\u VERIFY\u FAILED]CERTIFICATE VERIFY FAILED(\u ssl.c:600)。您关闭验证的解决方案就是诀窍。@Tim,异常的完整信息指向异常链中的错误源,不是吗?是的--没有try/except,所有正确的信息都会显示出来。我用try/except屏蔽了错误,只得到了我的异常文本+“无法连接到www.whitehouse.gov:443”。如果我建立了裸连接,我会看到完整的回溯——从ssl.SSLError开始,以aiohttp.errors.clientorror结束。经验教训(在开发代码时不要掩盖异常!)在
TCPConnector
中设置
ssl=False
时,我通常会收到相同的异常。这让人困惑。。。根据,
Purpose.CLIENT\u AUTH
用于创建服务器端套接字。很好,我忽略了这一点。查看
create\u default\u context()
的源代码,似乎可以使用
ssl.Purpose.CLIENT\u AUTH
禁用或选择证书检查。