10.1. endpoint แรกของคุณ#
ก่อนที่กล้องจะทำสิ่งที่น่าสนใจได้ ส่วนที่เหลือของเครือข่ายจะต้องสามารถเข้าถึงมันได้ก่อน สิ่งที่ง่ายที่สุดในการพิสูจน์ว่าเซิร์ฟเวอร์ยังทำงานอยู่คือ HTTP endpoint เส้นทางเดียวที่ส่งคืน JSON บางอย่าง:
from microdot import Microdot
app = Microdot()
frame_count = 0
trigger_count = 0
@app.get('/status')
async def status(request):
return {'frames': frame_count, 'triggers': trigger_count}
app.run(host='0.0.0.0', port=80)
รันใน IDE จากเครื่องอื่นในเครือข่าย LAN เปิด http://<cam-ip>/status เบราว์เซอร์จะแสดง:
{"frames": 0, "triggers": 0}
ตัวนับเป็นเพียงตัวแทนชั่วคราว -- ยังไม่มีอะไรแตะต้องมัน -- แต่คำขอได้ผ่านเครือข่าย กล้องได้กำหนดเส้นทาง รันตัวจัดการ และส่ง JSON กลับมาแล้ว
10.1.1. แต่ละบรรทัดทำอะไร#
สร้างอินสแตนซ์ microdot.Microdot หนึ่งตัวต่อสคริปต์ อินสแตนซ์นั้นเป็นเจ้าของตารางการกำหนดเส้นทาง ตัวจัดการข้อผิดพลาด และวงจรชีวิต (start, serve, stop) แอปพลิเคชันขนาดใหญ่แบ่งออกเป็นหลายโมดูล Python แต่ยังคงใช้อ็อบเจกต์ app เดียวร่วมกัน
@app.get('/status') คือตัวตกแต่งเส้นทาง เราใช้เฉพาะ microdot.Microdot.get() ที่นี่ post(), put(), และ delete() จะปรากฏในหน้าถัดไปเมื่อกล้องเริ่มรับการเขียน
ตัวจัดการเส้นทางทุกตัวเป็น asyncio coroutine และรับคำขอเป็นอาร์กิวเมนต์แรก ตัวจัดการไม่จำเป็นต้องใช้ request -- ตัวนี้ไม่ได้ใช้มัน -- แต่พารามิเตอร์จะอยู่ที่นั่นเสมอเพื่อให้ลายเซ็นสอดคล้องกัน
การคืน dict เป็นวิธีที่สั้นที่สุดในการส่ง JSON Microdot จะแปลง dict เป็น JSON โดยอัตโนมัติและกำหนด Content-Type: application/json ไว้ในการตอบสนอง การคืนสตริงจะส่ง text/plain การคืน microdot.Response อย่างชัดเจนเป็นรูปแบบยาว -- จำเป็นเมื่อเนื้อหาเป็นไบนารีหรือเมื่อการตอบสนองต้องการส่วนหัวที่กำหนดเอง
app.run(host='0.0.0.0', port=80) เริ่มต้นเซิร์ฟเวอร์ 0.0.0.0 หมายถึง รับฟังบนทุก interface ที่กล้องมี -- ทั้ง ethernet แบบใช้สายและ wifi STA หากทั้งสองทำงานอยู่ พอร์ต 80 คือค่าเริ่มต้น HTTP ดังนั้นเบราว์เซอร์ไม่จำเป็นต้องพิมพ์หมายเลขพอร์ต
10.1.2. คำขอหนึ่งครั้ง จากต้นจนจบ#
โทรศัพท์เปิดการเชื่อมต่อ TCP เขียนบรรทัดคำขอและส่วนหัว แล้วรอ กล้องอ่านไบต์จาก socket แยกวิเคราะห์เป็นอ็อบเจกต์ microdot.Request จับคู่เส้นทางและ method กับตารางการกำหนดเส้นทาง รอ coroutine ของตัวจัดการ แปลงสิ่งที่ส่งคืน เขียนบรรทัดสถานะ ส่วนหัว และเนื้อหากลับลง socket จากนั้นปิดการเชื่อมต่อ (ค่าเริ่มต้น HTTP/1.0) หรือนำมาใช้ใหม่ (HTTP/1.1 ด้วย Connection: keep-alive) การแลกเปลี่ยนทั้งหมดใช้เวลาประมาณเท่ากับเวลาที่เครือข่ายใช้ไปกลับบวกกับสิ่งที่ตัวจัดการทำ
10.1.3. หมายเหตุเกี่ยวกับการบล็อก#
run() บล็อก -- มันไม่ส่งคืนจนกว่าเซิร์ฟเวอร์จะหยุด ซึ่งเหมาะสำหรับเซิร์ฟเวอร์ที่มีวัตถุประสงค์เดียว แอปที่ยังจับภาพเฟรมหรือรัน coroutine อื่น ๆ จะใช้ start_server() ภายใน asyncio.run() แทน เพื่อให้ HTTP server สามารถแบ่งปัน loop กับทุกอย่างอื่น
แอปตอบสนองต่อ URL เดียว