10.1. Din första endpoint¶
Innan kameran kan göra något intressant måste resten av nätverket kunna nå den. Det billigaste sättet att bevisa att servern lever är en HTTP-endpoint med en enda rutt som returnerar lite 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)
Kör det i IDE:n. Öppna http://<cam-ip>/status från valfri annan maskin i det lokala nätverket. Webbläsaren visar:
{"frames": 0, "triggers": 0}
Räknarna är platshållare – ingenting rör dem ännu – men begäran tog sig över nätverket, kameran dirigerade den, körde en hanterare och skickade tillbaka JSON.
10.1.1. Vad varje rad gör¶
En microdot.Microdot-instans per skript. Instansen äger ruttabellen, felhanterarna och livscykeln (start, betjäning, stopp). Stora appar delas upp i flera Python-moduler men delar fortfarande ett enda app-objekt.
@app.get('/status') är ruttdekoratorn. Vi använder bara microdot.Microdot.get() här; post(), put() och delete() dyker upp på senare sidor när kameran börjar acceptera skrivningar.
Varje rutthanterare är en asyncio-coroutine och tar emot begäran som sitt första argument. Hanteraren behöver inte använda request – den här ignorerar det – men parametern finns alltid där så att signaturen är konsekvent.
Att returnera en dict är det kortaste sättet att skicka JSON. Microdot serialiserar dicten till JSON automatiskt och sätter Content-Type: application/json på svaret. Att returnera en sträng skickar text/plain. Att returnera en microdot.Response explicit är den långa formen – som behövs när kroppen är binär eller när svaret vill ha anpassade headers.
app.run(host='0.0.0.0', port=80) startar servern. 0.0.0.0 betyder lyssna på varje gränssnitt kameran har – både det kabelanslutna ethernet och wifi-STA:n, om båda är uppe. Port 80 är HTTP-standarden, så webbläsare behöver inte ange ett portnummer.
10.1.2. En begäran, från början till slut¶
Telefonen öppnar en TCP-anslutning, skriver begäranraden och headers och väntar. Kameran läser byten från socketen, tolkar dem till ett microdot.Request-objekt, matchar sökvägen och metoden mot ruttabellen, inväntar hanterar-coroutinen, serialiserar vad den än returnerade, skriver tillbaka en statusrad, headers och kropp ner i socketen och stänger sedan anslutningen (HTTP/1.0-standard) eller återanvänder den (HTTP/1.1 med Connection: keep-alive). Hela utbytet tar ungefär så lång tid som nätverkets tur och retur plus vad hanteraren än gjorde.
10.1.3. En anmärkning om blockering¶
run() är blockerande – den returnerar aldrig förrän servern stoppas. Det är bra för en server med ett enda syfte. En app som också fångar bildrutor eller kör andra coroutiner använder start_server() inuti en asyncio.run() istället, så att HTTP-servern kan dela loopen med allt annat.
Appen svarar på en URL.