python网络编程之aiohttp
aiohttp简介
aiohttp是一个建立在asyncio上的,既支持http又支持websocket的一个库。并且同时支持客户端和服务端。
官方文档:
https://docs.aiohttp.org/en/stable/
这篇文章主要记述aiohttp的http的使用
aiohttp for http client
实现客户端一个简单的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()
get 50818 length data from http://python.org
aiohttp for http server
接下来,看如何使用aiohttp分别开放一个get和post的接口供客户端调用
from aiohttp import web
#如果需要使用装饰器来路由uri的话,需要创建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():
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)
客户端调用如下:
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
1、我们先定义一个接口方法(即请求处理函数),该方法接收一个参数request.类型为:aiohttp.web_request.Request
2、然后创建一个Application的应用实例
3、把接口方法和对应的path注册到Application。有两种注册方法:
app.add_routes([web.get("/path", request_handler)])
使用装饰器,在request_handler方法上面加上@routes.get/post("/path")
get/post对应相应http请求GET和POST,当然也还有put和delete。同理。
如果想要使该接口即支持post请求也支持get请求,@routes.route("*", "/path")
4、最后运行Application实例。
1、客户端的每一次请求通过session完成,先创建一个ClientSession
2、然后使用调用session的get/post/put/delete方法去完成相应的请求,返回一个Response对象
3、通过返回的Response对象,我们可以获取返回消息(通过text()方法)
参数传递与参数获取
上面我们实现了简单的服务器的收发数据以及客户端的请求数据。接下来,看一下,request和post请求中的参数如何获取。以对一个灯的操作为例。
#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数据
data = {"result":True}
return web.json_response(data = data)
#熟悉post数据的读取
@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的数据内容,content是一个StreamReader
# body = str(body,encoding ='utf-8') #将读取到的byte数据转成字符串
# body_json = json.loads(body) #把字符串转换成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)
#带参数查询的get请求
#此函数接收一个参数name
@routes.get("/light/list")
async def get_online_lights(request):
#获取查询参数,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数据
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数据,需要使用json=而不是data=
#默认情况下会话(session)使用Python标准库里的json模块解析json信息。
# 但还可使用其他的json解析器。可以给ClientSession指定json_serialize参数来实现
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的内容获取,get请求的参数的传递与获取以及json数据的返回。基本上能够涉及到常用的网络请求。相关地方都有注释说明。所有代码均在pycharm中运行通过,python版本:3.8.5。官方文档里面还有很多介绍,很全面,比如Http表格的post请求,文件上传,重定向等。