快速开始
Request
不要为每个请求创建会话。每个应用程序很可能需要一个会话来执行所有请求。
更复杂的情况可能需要每个站点进行一次会话,例如一个用于Github,另一个用于Facebook API。无论如何,为每个请求建立会话是一个非常糟糕的主意。
会话内部包含一个连接池。连接重用和保持活动状态(默认情况下均处于启用状态)可能会提高整体性能。
简单请求
import aiohttp
async with aiohttp.ClientSession() as session:
async with session.get('http://httpbin.org/get') as resp:
print(resp.status)
print(await resp.text())
其他请求方法
session.post('http://httpbin.org/post', data=b'data')
session.put('http://httpbin.org/put', data=b'data')
session.delete('http://httpbin.org/delete')
session.head('http://httpbin.org/get')
session.options('http://httpbin.org/get')
session.patch('http://httpbin.org/patch', data=b'data')
非上下文
session = aiohttp.ClientSession()
async with session.get('...'):
# ...
await session.close()
传递参数
dict
params = {'key1': 'value1', 'key2': 'value2'}
async with session.get('http://httpbin.org/get',
params=params) as resp:
expect = 'http://httpbin.org/get?key2=value2&key1=value1'
assert str(resp.url) == expect
list
params = [('key', 'value1'), ('key', 'value2')]
async with session.get('http://httpbin.org/get',
params=params) as r:
expect = 'http://httpbin.org/get?key=value2&key=value1'
assert str(r.url) == expect
string
# 注意内容不是由库编码的。示例中+未被编码:
async with session.get('http://httpbin.org/get',
params='key=value+1') as r:
assert str(r.url) == 'http://httpbin.org/get?key=value+1'
注意
aiohttp在发送请求之前在内部执行URL规范化。
规范化通过IDNA编解码器对主机部分进行编码,并将重引用应用于路径和查询部分。
例如,URL(http://example.com/путь/%30?a=%31)转换为URL(http://example.com/%D0%BF%D1%83%D1%82%D1%8C/0?a=1)。
如果服务器接受精确的表示并且不重新引用URL本身,则有时不希望进行规范化。
要禁用规范化,请使用`encode = True`参数进行URL构建
await session.get(
URL('http://example.com/%30', encoded=True)
)
复杂POST
form-encoded
表单形式,字典形式
payload = {'key1': 'value1', 'key2': 'value2'}
async with session.post('http://httpbin.org/post',
data=payload) as resp:
print(await resp.text())
application/octet-stream
非表单形式,byte形式
async with session.post(url, data=b'x00Binary-datax00') as resp:
...
json
async with session.post(url, json={'example': 'test'}) as resp:
...
默认使用标准json
模块序列化,也可指定序列化器
import ujson
async with aiohttp.ClientSession(
json_serialize=ujson.dumps) as session:
await session.post(url, json={'test': 'object'})
text
async with session.post(url, data='Тест') as resp:
...
Multipart-encoded
url = 'http://httpbin.org/post'
files = {'file': open('report.xls', 'rb')}
await session.post(url, data=files)
设置文件名和内容类型
url = 'http://httpbin.org/post'
data = FormData()
data.add_field('file',
open('report.xls', 'rb'),
filename='report.xls',
content_type='application/vnd.ms-excel')
await session.post(url, data=data)
streaming
aiohttp支持多种类型的流上传,这使您可以发送大文件而无需将其读入内存。
文件对象
with open('massive-body', 'rb') as f:
await session.post('http://httpbin.org/post', data=f)
异步生成器
async def file_sender(file_name=None):
async with aiofiles.open(file_name, 'rb') as f:
chunk = await f.read(64*1024)
while chunk:
yield chunk
chunk = await f.read(64*1024)
# Then you can use file_sender as a data provider:
async with session.post('http://httpbin.org/post',
data=file_sender(file_name='huge_file')) as resp:
print(await resp.text())
因为content属性是StreamReader(提供了异步迭代器协议),可以将获取和发布请求链接在一起:
resp = await session.get('http://python.org')
await session.post('http://httpbin.org/post',
data=resp.content)
Response
简单响应
async with session.get('https://api.github.com/events') as resp:
print(resp.status)
print(await resp.text())
# 200
# '[{"created_at":"2015-06-12T14:06:22Z","public":true,"actor":{...
aiohttp自动解码服务器中的内容。也可指定自定义编码
await resp.text(encoding='windows-1251')
二进制
print(await resp.read())
# b'[{"created_at":"2015-06-12T14:06:22Z","public":true,"actor":{...
gzip
和deflate
传输编码会自动为您解码。
可以启用brotli
传输编码支持,只需安装brotlipy.。
JSON
使用默认的json解码器,也可以为json()
调用指定自定义编码和解码器功能。
async with session.get('https://api.github.com/events') as resp:
print(await resp.json())
Stream
尽管read()
,json()
和text()
方法非常方便,但您应谨慎使用它们。所有这些方法将整个响应加载到内存中。可以使用content
属性。它是aiohttp.StreamReader
类的实例。
gzip
和deflate
传输编码会自动解码
从内容中显式读取之后,不能使用read(),json(),text()
async with session.get('https://api.github.com/events') as resp:
await resp.content.read(10)
但是,一般而言,您应该使用以下模式来保存流式传输到文件中的内容
with open(filename, 'wb') as fd:
while True:
chunk = await resp.content.read(chunk_size)
if not chunk:
break
fd.write(chunk)
超时
超时设置存储在ClientTimeout数据结构中。
默认情况下,aiohttp总共使用5分钟的超时时间,这意味着整个操作应在5分钟内完成。
session
中覆盖
timeout = aiohttp.ClientTimeout(total=60)
async with aiohttp.ClientSession(timeout=timeout) as session:
...
request
中覆盖
async with session.get(url, timeout=timeout) as resp:
...
默认形式
aiohttp.ClientTimeout(total=5*60, connect=None,
sock_connect=None, sock_read=None)
WebSockets
内置了websocket服务
ws = aiohttp.ClientSession.ws_connect() # 连接ws服务器
await ws.receive() # 获取回复信息
await ws.sen_str('data') # 发送信息
示例
async with session.ws_connect('http://example.org/ws') as ws:
async for msg in ws: # await ws.receive()
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