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. คำขอหนึ่งครั้ง จากต้นจนจบ

The phone opens a TCP connection to the cam, sends an HTTP request, the cam parses, routes, runs the handler, then writes a response back.

โทรศัพท์เปิดการเชื่อมต่อ 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 เดียว