aiohttp簡介
aiohttp是一個建立在asyncio上的,既支持http又支持websocket的一個庫。并且同時支持客戶端和服務(wù)端。
官方文檔:https://docs.aiohttp.org/en/stable/
這篇文章主要記述aiohttp的http的使用
aiohttp for http client
實(shí)現(xiàn)客戶端一個簡單的get請求
import aiohttp
import asyncio
async def get_url(url):
async with aiohttp.ClientSession() as session:
async with session.get(url) as resp:
print(resp.status)
result = await resp.text()
print("get {} length data from {}".format(len(result),url))
async def main():
url = "http://python.org"
await get_url(url)
await main()
200
get 50818 length data from http://python.org
aiohttp for http server
接下來,看如何使用aiohttp分別開放一個get和post的接口供客戶端調(diào)用
from aiohttp import web
#如果需要使用裝飾器來路由uri的話,需要創(chuàng)建RouteTableDef類的對象來獲取一個裝飾器
routes = web.RouteTableDef()
@routes.get("/get")
async def get_req(request):
print("this is get req")
return web.Response(text="Hello World")
@routes.post("/post")
async def post_req(request):
print("this is post request")
return web.Response(text="Post Success")
@routes.route("*", "/all")#支持GET/POST/PUT/DELETE
async def all_handler(request):
print(request.method)
print(type(request))
print("handle all request")
return web.Response(text="All")
def main():
pass
if __name__ == '__main__':
app = web.Application()
#如果不使用裝飾器的話, 添加如下代碼
# app.add_routes([web.get("/get", get_req),
# web.post("/post",post_req)])
#如果使用裝飾器,則添加如下一行
app.add_routes(routes)
web.run_app(app)
客戶端調(diào)用如下:
import aiohttp
import asyncio
async def get_request():
async with aiohttp.ClientSession() as session:
url = "http://0.0.0.0:8080/get"
async with session.get(url) as resp:
print("status:{}".format(resp.status))
text = await resp.text()
print(text)
async def post_request():
url = "http://0.0.0.0:8080/post"
async with aiohttp.ClientSession() as session:
async with session.post(url, data={"a": 1}) as resp:
print("status:{}".format(resp.status))
res = await resp.text()
print(res)
async def main():
await get_request()
await post_request()
if __name__ == '__main__':
#asyncio.run(main())
await main()
status:200
Hello World
status:200
Post Success
服務(wù)端:
1、我們先定義一個接口方法(即請求處理函數(shù)),該方法接收一個參數(shù)request.類型為:aiohttp.web_request.Request
2、然后創(chuàng)建一個Application的應(yīng)用實(shí)例
3、把接口方法和對應(yīng)的path注冊到Application。有兩種注冊方法:
- app.add_routes([web.get("/path", request_handler)])
- 使用裝飾器,在request_handler方法上面加上@routes.get/post("/path")
get/post對應(yīng)相應(yīng)http請求GET和POST,當(dāng)然也還有put和delete。同理。
如果想要使該接口即支持post請求也支持get請求,@routes.route("*", "/path")
4、最后運(yùn)行Application實(shí)例。
客戶端:
1、客戶端的每一次請求通過session完成,先創(chuàng)建一個ClientSession
2、然后使用調(diào)用session的get/post/put/delete方法去完成相應(yīng)的請求,返回一個Response對象
3、通過返回的Response對象,我們可以獲取返回消息(通過text()方法)
參數(shù)傳遞與參數(shù)獲取
上面我們實(shí)現(xiàn)了簡單的服務(wù)器的收發(fā)數(shù)據(jù)以及客戶端的請求數(shù)據(jù)。接下來,看一下,request和post請求中的參數(shù)如何獲取。以對一個燈的操作為例。
#server.py
import asyncio
from aiohttp import web
import json
routes = web.RouteTableDef()
#接受uri中可傳變量
@routes.get("/light/on/{addr}")
async def turn_on(request):
#通過match_info可以獲取path中的變量信息
addr = request.match_info['addr']
await asyncio.sleep(1) #假裝去處理事情
print("turn on the light:{}".format(addr))
#返回一個字符串
return web.Response(text="success")
@routes.get("/light/off/{addr}")
async def turn_off(request):
#通過match_info可以獲取path中的變量信息
addr = request.match_info['addr']
await asyncio.sleep(1) #假裝去處理事情
print("turn off the light:{}".format(addr))
#返回一個json數(shù)據(jù)
data = {"result":True}
return web.json_response(data = data)
#熟悉post數(shù)據(jù)的讀取
@routes.post("/light/set_color/{addr}")
async def set_color(request):
addr = request.match_info['addr']
if request.can_read_body:
print("has body")
#如果傳遞的是data=,則可以使用通過content讀取
# body = await request.content.read() #讀取post的數(shù)據(jù)內(nèi)容,content是一個StreamReader
# body = str(body,encoding ='utf-8') #將讀取到的byte數(shù)據(jù)轉(zhuǎn)成字符串
# body_json = json.loads(body) #把字符串轉(zhuǎn)換成json
body_json = await request.json()
print("get post data:{}".format(body_json))
print(type(body_json))
assert body_json["color"]
color = body_json["color"]
print("set color to:{} for light:{}".format(color,addr))
data = {"result":True,"color":color}
return web.json_response(data)
else:
data = {"result":False,"err":"invalid params"}
return web.json_response(data)
#帶參數(shù)查詢的get請求
#此函數(shù)接收一個參數(shù)name
@routes.get("/light/list")
async def get_online_lights(request):
#獲取查詢參數(shù),request.query是一個MultiDictProxy對象,我們可以向字典一樣操作它
params = request.query
name = params.get("name") #使用get方法,如果不存在該key值,會返回None
if name is None:
err = {"result":False,"err":"invalid params"}
return web.json_response(err)
print("query all light for {}".format(name))
light_list = ["00-12-4b-00-54-23-09","00-12-4b-00-54-24-01"]
data = {"light_list":light_list,"name":name}
return web.json_response(data)
def main():
app = web.Application()
app.add_routes(routes)
web.run_app(app)
if __name__== "__main__":
main()
#client.py
import json
import aiohttp
import asyncio
import json
import ujson
async def turn_on_light(addr):
async with aiohttp.ClientSession() as session:
url = "http://0.0.0.0:8080/light/on/"+addr
async with session.get(url) as resp:
if resp.status == 200:
result = await resp.text()
print("turn on result is:{}".format(result))
async def turn_off_light(addr):
async with aiohttp.ClientSession() as session:
url = "http://0.0.0.0:8080/light/off/"+addr
async with session.get(url) as resp:
if resp.status == 200:
result = await resp.json() #獲取返回的json數(shù)據(jù)
print("turn off result is:{}".format(result["result"]))
async def set_color(addr):
async with aiohttp.ClientSession() as session:
url = "http://0.0.0.0:8080/light/set_color/"+addr
data = {"color":"f0f0f0"}
headers = {"content-type":"application/json"}
#可以直接傳遞json數(shù)據(jù),需要使用json=而不是data=
#默認(rèn)情況下會話(session)使用Python標(biāo)準(zhǔn)庫里的json模塊解析json信息。
# 但還可使用其他的json解析器??梢越oClientSession指定json_serialize參數(shù)來實(shí)現(xiàn)
async with session.post(url,json=data,headers=headers) as resp:
if resp.status == 200:
result = await resp.json()
print("set color result is:{}".format(result))
else:
print(resp.status)
async def query_lights_list():
async with aiohttp.ClientSession() as session:
url = "http://0.0.0.0:8080/light/list"
params = {"name":"H.H"}
headers = {"content-type":"application/json"}
async with session.get(url,params=params)as resp:
if resp.status == 200:
result = await resp.text()
print("query light list is:{}".format(result))
else:
print(resp.status)
async def main():
light_addr = "00-12-4b-00-54-23-09"
await turn_on_light(light_addr)
await turn_off_light(light_addr)
await set_color(light_addr)
await query_lights_list()
if __name__ == "__main__":
asyncio.run(main())
上面的例子分別涉及到了uri存在變量,post的內(nèi)容獲取,get請求的參數(shù)的傳遞與獲取以及json數(shù)據(jù)的返回?;旧夏軌蛏婕暗匠S玫木W(wǎng)絡(luò)請求。相關(guān)地方都有注釋說明。所有代碼均在pycharm中運(yùn)行通過,python版本:3.8.5。官方文檔里面還有很多介紹,很全面,比如Http表格的post請求,文件上傳,重定向等。