python網(wǎng)絡(luò)編程之a(chǎn)iohttp

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請求,文件上傳,重定向等。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1. 進(jìn)程、線程、協(xié)程的概念 進(jìn)程:CPU是系統(tǒng)進(jìn)行資源分配和調(diào)度的基本單位,進(jìn)程是程序執(zhí)行的實(shí)體,是線程執(zhí)行的容...
    阿尼奧賽喲閱讀 494評論 0 0
  • PS:簡書的網(wǎng)址真不是給人看的。。。我單獨(dú)開了一個網(wǎng)址可以重定向到我的簡書主頁。博客地址:flutterall.c...
    徐愛卿閱讀 7,117評論 21 97
  • 網(wǎng)絡(luò) 理論模型,分為七層物理層數(shù)據(jù)鏈路層傳輸層會話層表示層應(yīng)用層 實(shí)際應(yīng)用,分為四層鏈路層網(wǎng)絡(luò)層傳輸層應(yīng)用層 IP...
    FlyingLittlePG閱讀 961評論 0 0
  • python****網(wǎng)絡(luò)編程常用庫使用手冊 一、urllib3 ** Urllib3****是一個功能強(qiáng)大,條理清...
    奕劍聽雨閱讀 257評論 0 0
  • 1. 概述 Web工作方式 對于普通的上網(wǎng)過程,系統(tǒng)其實(shí)是這樣做的:瀏覽器本身是一個客戶端,當(dāng)你輸入URL的時候,...
    泡泡龍吐泡泡閱讀 2,331評論 0 5

友情鏈接更多精彩內(nèi)容