作为客户端使用

aiohttp是一个基于asyncio模块的异步HTTP客户端,所以在使用时,要打开思路,以异步的方式思考问题。

进行基本访问

使用aiohttp模块访问指定URL十分简单,只需要调用相应的HTTP谓词方法即可。基本使用方式如下:

import aiohttp

async with aiohttp.ClientSession() as session:
	async with session.get('http://www.baidu.com/') as resp:
		print(resp.status)
		print(await resp.text())

示例代码中使用ClientSession()创建了一个用于访问的会话,之后使用这个会话的不同谓词方法来进行HTTP访问,并返回ClientResponse类型的结果。

会话的调用函数一般会将其排入asyncio.get_event_loop()中,参考之前并行计算中介绍的使用.run_until_complete()方法排入异步任务的示例。

在实际使用中,可以在整个应用中使用一个会话,不要对于每次HTTP访问都创建一个会话,因为会话本身会在服务端留下一些信息。

会话可以使用的HTTP访问方法支持大部分的HTTP谓词,其使用格式如下:

  • sesison.get('url')
  • session.post('url', data=b'data')
  • session.put('url', data=b'data')
  • sesison.delete('url')
  • sesison.head('url')
  • sesison.options('url')
  • session.patch('url', data=b'data')

解析响应内容

会话访问指定URL返回的ClientResponse类型的结果中携带了全部服务器的响应内容。其中使用gzip和deflate压缩传输的内容将会被自动解压缩。

通常可以使用response.text()这个异步方法来获取响应的主体内容。response.status属性可以用来获取服务器响应的HTTP状态码。如果要获取二进制响应体内容,可以使用response.read()这个异步方法。此外还可以直接使用response.json()异步方法来获取JSON格式的响应体并直接进行解析。

如果响应体内容很长,可以直接使用response.content属性来进行响应流的操作。

传递Query参数

HTTP谓词一般都可以携带Query参数。aiohttp在进行HTTP访问时,不需要将Query参数手工拼入URL中,只需要将Query参数内容传入谓词方法的params参数中。

params参数接受字典({'key': 'value'})、元组列表[('key', 'value')]等类型的内容。

具体使用可参考以下示例:

params = {'key1': 'value1', 'key2': 'value2'}

async with session.get('http://www.baidu.com/', params=params) as r:
	assert str(r.url) == 'http://www.baidu.com/?key1=value1&key2=value2'

传递JSON参数

在使用POST等方法时,可以使用data参数来上传字典类型的表单数据。但是在目前的项目开发中,使用JSON格式的表单数据会变得更加常见。

aiohttp也支持使用JSON格式的表单数据,只需要使用字典类型的数据传递给json参数而不是data参数即可,例如:session.post(url, json={'key': 'value'})

上传文件

上传文件也是HTTP访问中经常要做的操作之一,aiohttp中上传文件非常简单。以下是一个上传文件的示例。

files = {'file': open(path, 'rb')}
await session.post(url, data=files)

或者还可以使用FormData()方法来对表单数据进行精细化配置。除此之外,可以使用流来上传文件,以下给出一个使用流上传文件的最简单示例。

with open(path, 'rb') as f:
	await session.post(url, data=f)

或者还可以使用异步生成器来传输更大的文件。

async def file_sender(file_name=None):
	async with asiofiles.open(file_name, 'rb') as f:
		chunk = await f.read(64*1024)
		while chunk:
			yield chunk
			chunk = await f.read(64*1024)

async with session.post(url, data=file_sender(path)) as resp:
	print(await resp.text())

Websocket访问

aiohttp功能库内置了WebSocket的支持,使用会话连接WebSocket会得到一个ClientWebSocketResponse类型实例,用来进行实时通讯。可以仿照下例来书写WebSocket访问。

async with session.ws_connect(ws_url) as ws:
	async for msg in ws:
		if msg.type == aiohttp.WSMsgType.TEXT:
			if msg.data == 'close cmd':
				await ws.close
				break;
			else:
				await ws.send_str(msg.data + '/answer')
		elif msg.type == aiohttp.WSMsgType.ERROR:
			break

WebSocket在同一时刻只能有一个读取任务,但是可以有多个写入任务。

头信息

头信息是HTTP请求中重要的信息储存位置,所有HTTP谓词访问方法都支持使用headers参数接受一个字典来对HTTP请求的头信息进行设置。

此外,跟随头信息设定的还有Cookies信息,这是使用coookies参数来设定的,Cookies参数同样接受一个字典类型的对象。

对于服务器响应信息中的头信息和Cookies信息的访问,可以分别通过headerscookies属性来访问,这两个属性中保存的信息都是字典类型,可以直接使用键值来访问。

连接池

默认情况下,aiohttp会同时并发进行全部的HTTP请求(默认上限为100个请求)。但是很多情况下需要对同时连接数进行限制,这时就可以使用连接池技术。aiohttp功能库提供了TCPConnector()方法,允许用户对HTTP连接进行细致的调控,连接池就是使用TCPConnector类来完成的配置。

conn = aiohttp.TCPConnector(limit=10) # 限制全局并发连接数为10个
conn = aiohttp.TCPConnector(limit_per_host=20) # 限制每个host的并发连接数为20个
session = aiohttp.ClientSession(connector=conn) # 使用TCPConnector初始化会话。