Ga naar hoofdinhoud

Laat het aan anderen zien

Je server draait, maar alleen voor jou. 127.0.0.1 betekent letterlijk "deze computer": typ dat adres op de laptop van je buurman en je komt niet bij jouw server uit. Dat is jammer, want een server is er zodat anderen erbij kunnen. Hier zet je je project open voor de rest van het lokale netwerk.

Waarom niemand anders erbij kan​

Als je fastapi dev main.py start, staat er in de terminal iets als:

Server started at http://127.0.0.1:8000

Dat adres luistert bewust alleen naar verzoeken van je eigen computer. Tijdens het bouwen is dat handig, want dan staat je halfafgemaakte gastenboek niet meteen open voor de hele school.

Openzetten​

Start je server met een extra optie:

fastapi dev main.py --host 0.0.0.0

0.0.0.0 betekent: luister naar verzoeken die van buiten binnenkomen, niet alleen van deze computer. In de terminal staat nu:

Server started at http://0.0.0.0:8000

Dat is geen adres om naar toe te gaan, en ook niet om door te geven. Zelf blijf je http://127.0.0.1:8000 gebruiken; je klasgenoot krijgt het adres hieronder.

Nu heb je nog het adres van je computer op het netwerk nodig:

# Windows
ipconfig

# macOS
ipconfig getifaddr en0

# Linux
ip addr

Op Windows zoek je de regel IPv4-adres (in het Engels IPv4 Address); macOS geeft alleen het adres. Het begint meestal met 192.168., 10. of 172.. Dat is jouw computer op dit netwerk. Je klasgenoot typt dan bijvoorbeeld:

http://192.168.1.42:8000/berichten

Het is hetzelfde project met dezelfde database, maar nu ziet iemand anders het.

pas op

Zolang je server op 0.0.0.0 draait kan iedereen op hetzelfde netwerk bij je pagina's, en ook bij je formulieren. Zet 'm weer op de gewone manier aan als je klaar bent met testen. En zet nooit iets in je code dat je liever niet deelt: een wachtwoord in main.py is een wachtwoord dat je weggeeft.

Nu telt alles wat je hebt geleerd​

Nu is Server of browser? geen theorie meer. Zolang jij de enige bezoeker was, kon je jezelf vertrouwen. Vanaf nu vult iemand anders je formulier in, en die kan van alles typen dat je niet had verwacht.

De controles die je in Python hebt gezet doen nu echt werk. De maxlength in je HTML nog steeds niet.

Wat je nog meer kunt afschermen, zoals de wachtwoorden van je gebruikers, wie welk bericht mag verwijderen en HTML die een bezoeker invult, staat in de reeks Veiligheid.

Buiten de school​

Een adres dat begint met 192.168. werkt alleen binnen hetzelfde netwerk. Wil je je project vanaf thuis bereikbaar maken, dan heb je een computer nodig die altijd aanstaat en een vast adres heeft: een server bij een hostingpartij, of een dienst die je project voor je draait.

Dat valt buiten deze cursus, maar het is dezelfde main.py. Wat je hier hebt gebouwd is niet een oefenversie van een echte webapplicatie; het is er een.

Gaat er iets mis?

Kan je klasgenoot er niet bij? Meestal mist --host 0.0.0.0, of zitten jullie niet op hetzelfde netwerk. Meer oplossingen staan op Er gaat iets mis.

Controlevraag
Je klasgenoot is ingelogd op jouw gastenboek. Hij haalt in Elementen de maxlength van het berichtveld weg en verstuurt een bericht van 200 tekens. Wat ziet hij in Netwerk?
Kies wat jij denkt. Bij het goede antwoord zie je de uitleg.

Opdrachten​

Opdracht 1: Predict - Wie kan erbij?​

Je server draait op 127.0.0.1:8000. Je klasgenoot zit op hetzelfde wifi-netwerk en typt http://127.0.0.1:8000 in zijn browser.

Voorspel
Wat ziet hij?
Kies wat jij denkt. Bij het goede antwoord zie je de uitleg.

Opdracht 2: Run - Samen testen​

Start je server met --host 0.0.0.0, zoek je adres op zoals hierboven, en laat iemand naast je een account maken en een bericht achterlaten in je gastenboek. Kijk in je eigen terminal wat er gebeurt terwijl hij typt en verstuurt.

Tip

Lukt het niet? Kijk of jullie op hetzelfde netwerk zitten. Op school is dat niet vanzelfsprekend, want het gastennetwerk staat los van het schoolnetwerk. Een firewall die om toestemming vraagt moet je toestaan.

Opdracht 3: Investigate - Wat ziet de server van hem?​

Kijk in je terminal naar de regels die verschijnen als je klasgenoot iets doet.

Antwoord

Je ziet zijn verzoeken langskomen, met vooraan zijn adres op het netwerk (bijvoorbeeld 192.168.1.57) en verder het pad en de statuscode: precies de stappen 2 tot en met 6 uit Zo werkt het: klikken en versturen. Wat hij in het formulier typte terwijl hij nog aan het invullen was, zie je níét, want dat gebeurde in zijn browser. Bouwde je het htmx-recept Zoeken terwijl je typt, dan zie je de zoekwoorden wél: elk ervan is een verzoek, zoals GET /berichten/lijst?term=hoi.

Opdracht 4: Make - Een bezoekersteller​

Houd bij hoe vaak /berichten is opgevraagd en toon dat onderaan de pagina.

Tip

Dit moet bewaard blijven en voor iedereen gelden, dus het hoort in je database. Zet de teller in een eigen databasebestand, los van je berichten. Lees de stand met db.get("aantal", 0), tel er één bij op, sla op, en stuur het getal mee naar je template.

Antwoord

Zet deze regels vooraan in je GET /berichten, vóór het ophalen van de berichten:

with SqliteDict("bezoeken.db") as teller_db:
bezoeken = teller_db.get("aantal", 0) + 1
teller_db["aantal"] = bezoeken
teller_db.commit()

En zet "bezoeken": bezoeken erbij in de dictionary voor de template. Gebruik je htmx om te verversen, zet de teller dan niet in GET /berichten/lijst: dan telt elke verversing als bezoek.

In je template: <p>Deze pagina is {{ bezoeken }} keer bekeken.</p>

Houd de teller in bezoeken.db, niet in gastenboek.db. Zet je hem er wél bij, dan komt hij tussen je berichten terecht: je lijst krijgt er een regel bij die geen naam en geen bericht heeft, en {% for sleutel, bericht in berichten %} gaat er raar van doen. Twee soorten gegevens, twee bestanden.

Opdracht 5: Make - Hoe laat was het?​

Sla bij elk bericht op wanneer het is achtergelaten, en toon dat in de lijst.

Tip

Je hebt de tijd al: de sleutel bericht_<nanoseconden> bevat hem. Maar leesbaarder is een apart veld. datetime.now().strftime("%H:%M") geeft je "14:32".

Antwoord

Zet from datetime import datetime bij je imports. Vervang in je POST /gastenboek alleen de dictionary van het bericht; wat links van het =-teken staat en de rest van het endpoint blijven hetzelfde. De naam komt uit de sessie, zoals in Onthouden op de server: sessies:

db[f"bericht_{time.time_ns()}"] = {
"naam": mijn["naam"],
"bericht": bericht,
"tijd": datetime.now().strftime("%H:%M"),
}

In je template zet je {% if bericht.tijd %}{{ bericht.tijd }} —{% endif %} vooraan in de <li>, vóór de naam.

Berichten die je vóór deze wijziging hebt opgeslagen hebben geen tijd. Jinja2 crasht daar niet op, en de {% if %} slaat dan de tijd en het streepje over.