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 เดียว