Python3.5 asyncio中await后无法获取HTTP请求数据问题
为什么aiohttp响应的json()/text()返回协程而非实际内容?
我尝试用Python 3.5的aiohttp库写了一个简单的异步HTTP请求包装函数:
async def perform_async_http(self, url, method, data='', headers={}): async with aiohttp.ClientSession() as session: if method.lower() == 'get': async with session.get(url, headers=headers) as response: return response async with session.post(url, data=data, headers=headers) as response: return response
之后我用这个函数写了下面的代码:
http_future = self.perform_async_http(url, "post", data, headers) res = await http_future print(res.json())
问题是res.json()或者res.text()返回的是一个协程,没办法拿到实际的响应内容;但访问res.status这类属性却能正常工作。我原本以为await http_future会在就绪时返回实际值,想请教下我哪里理解错了?
问题解析与解决方法
其实你这里的误解点很清晰:你通过await http_future确实拿到了真实的aiohttp.ClientResponse对象——这就是为什么res.status这类属性能直接访问,因为它们是响应对象的同步属性,不需要IO操作就能获取。
但json()、text()、read()这些方法不一样,它们需要从网络流中读取完整的响应体内容,这个过程是异步IO操作,所以aiohttp把它们设计成了协程函数。也就是说,调用这些方法只会返回一个协程对象,你必须再用await去等待它执行完成,才能拿到实际的响应内容。
修正后的代码应该是这样:
http_future = self.perform_async_http(url, "post", data, headers) res = await http_future # 给json()加上await,等待响应体读取完成 response_content = await res.json() print(response_content)
另外给你提个小细节优化:你的函数里headers={}作为默认参数是有坑的——Python中默认参数是在函数定义时创建的,多次调用函数会复用同一个字典实例,可能导致意外的头部参数污染。建议改成下面的写法:
async def perform_async_http(self, url, method, data='', headers=None): # 如果没传headers,就初始化一个新字典 headers = headers or {} async with aiohttp.ClientSession() as session: if method.lower() == 'get': async with session.get(url, headers=headers) as response: return response async with session.post(url, data=data, headers=headers) as response: return response
内容的提问来源于stack exchange,提问作者Roy Rashti
相关产品推荐
相关产品推荐

