异步aiohttp请求失败,但同步请求成功

时间:2015-04-23 15:15:06

标签: python-3.x asynchronous python-asyncio aiohttp

使用以下代码,当我使用异步Cannot connect to host ...:443 ssl:True时,我得到aiohttp。当我使用同步requests时,它会成功。

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

4 个答案:

答案 0 :(得分:9)

我怀疑您的计算机上的证书验证链已损坏。 在Ubuntu上,一切正常,正如@dano所说。

无论如何,您可以通过创建自定义g.draw((Shape) new Rectangle( x, y, width, height));实例来禁用ssl验证:

Connector

BTW,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。另见https://github.com/aio-libs/aiohttp/issues/341

答案 1 :(得分:0)

请勿使用此应答,因为这等同于禁用证书检查。

Le Hibou在评论中指出,ssl.Purpose.CLIENT_AUTH用于在服务器端对客户端进行身份验证。

  

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

查看create_default_context()的代码表明,在这种情况下,可能禁用了证书检查,或者至少是可选的。


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

import aiohttp
import ssl


client = aiohttp.ClientSession()
client.post(
    'https://some.foo/bar/',
    json={"foo": "bar"},
    ssl=ssl.create_default_context(purpose=ssl.Purpose.CLIENT_AUTH))

这是使用request()ssl参数来设置与默认值不同的SSL上下文。默认值为ssl.create_default_context()

问题是ssl.create_default_context()的默认值为:

ssl.create_default_context(purpose=Purpose.SERVER_AUTH, cafile=None, capath=None, cadata=None)

在客户端上验证服务器证书时,Purpose.SERVER_AUTH似乎不起作用。验证为客户端时,请使用Purpose.CLIENT_AUTH

答案 2 :(得分:0)

在具有过期CA根证书的旧Linux服务器上,我遇到了同样的问题,并且在SSLContext中加载certifi CA证书包解决了该问题。

import aiohttp
import ssl
import certifi

ssl_context = ssl.create_default_context(cafile=certifi.where())
async with aiohttp.ClientSession() as session:
    async with session.get('https://some.foo/bar/', ssl=ssl_context) as response:
        print(await response.text())

答案 3 :(得分:0)

这对我有用:

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