4. Einen Webserver programmieren
4.5 Http GET und Http POST
Im letzten Abschnitt haben wir gesehen, wie der Browser dynamisch generierte Daten zum Server schicken kann. Dynamisch bedeutet hier, dass die Daten noch nicht im Code der HTML-Seite selbst vorhanden sind. Dynamisch sind zum Beispiel die Daten, die der Nutzer auf 06-enter-name/index.html in die Eingabefelder eingibt.
Die vom Benutzer eingegebenen Daten (im Beispiel Vor- und Nachname) wurden einfach in den URL des GET-Requests geschrieben. Schauen wir uns einmal an, wie dieser GET-Request aussieht (erinnern Sie sich: Browser und Server kommunizieren, indem Sie sich über eine TCP-Verbindung mehr oder weniger menschenlesbare HTTP-Nachrichten schicken).
GET /enter-name?firstname=Dominik&lastname=Scheder HTTP/1.1
Host: localhost:2002
Connection: keep-alive
sec-ch-ua: "Google Chrome";v="105", "Not)A;Brand";v="8", "Chromium";v="105"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "macOS"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://localhost:2002/
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7,de;q=0.6,da;q=0.5
Für uns ist nur die erste Zeile interessant. Sie enthält bereits alle Daten, die der
Nutzer
eingegeben hat.
Schreiben wir jetzt eine weitere kleine Anwendung, in der ein Nutzer einen Beitrag
schreiben
und
abschicken kann.
Um mehr Text schreiben und auch scrollen zu können, verwenden wir als Eingabe nicht
das <input>
-Tag, sondern den <textarea>
-Tag. Der Rest
sieht aber gleich
aus.
- Der Server: submit-via-GET.js
- Die HTML-Seite dazu: index.html
Starten Sie den Server und gehen auf localhost:4011 und geben Sie eine Nachricht ein. Achten Sie auf das, was in der Adresszeile erscheint. Hier sind zwei Screenshots:
Ich habe ein ungutes Gefühl. Was ist mit sehr langen Beiträgen? Gibt es denn eine Obergrenze, wie lange ein URL sein darf? Probieren Sie es aus! Schreiben Sie einen richtig langen Beitrag und sehen, wie lange es gutgeht. Bei mir waren 16384 Zeichen bereits zuviel. Das ist nicht besonders lange! Der Quelltext dieser HTML-Seite ist bereits um ein vielfaches länger. Auf Sistrix finden Sie einen Beitrag darüber, wie lange URLs sein dürfen. Anscheinend schreibt das HTTP-Protokol keine Obergrenze vor, empfiehlt aber
Various ad hoc limitations on request-line length are found in practice. It is RECOMMENDED that all HTTP senders and recipients support, at a minimum, request-line lengths of 8000 octets.
Jedenfalls können wir in Theorie und Praxis größere Datenmengen nicht als Query-String eines URLs verschicken. Hierfür gibt es einen weiteren HTTP-Request, nämlich POST.
Verschicken von Daten per POST
Für Sie als Entwickler, die die HTML-Seite oder den Server schreiben, ändert sich gar nicht so viel. Hier ist der Quelltext für einen express.js-Server, der GET benutzt und einen, der POST benutzt.
- Server, der mit GET sendet: submit-via-GET.js, index.html
- Server, der mit POST sendet: submit-via-POST.js, index.html
Ausschnitt aus index.htmlconst express = require('express');
const url = require('url');
const bodyParser = require("body-parser");
const portnumber = 4011;
const server = express();
server.use(express.static("."));
server.use(bodyParser.urlencoded({ extended: false, limit: '1mb' }));
server.get ('/submit-message', submitMessageGet);
server.listen(portnumber, function () {
console.log('listening at port ' + portnumber);
});
function submitMessageGet (req, res) {
data = url.parse(req.url, true).query;
var text = `<html>n<body>n`;
for (let key in data) {
text += `<p><strong>${key}:</strong> ${data[key]}</p>n`;
}
text += `</body>n</html>n`;
res.send(text);
}
<form action="submit-message" method="GET">
<div class="form-group">
<label for="username">Benutzername:</label>
<input name="username"><br>
<textarea name="user-message"></textarea>
</div>
<button type="submit" class="btn btn-default">Submit via GET</button>
</form>
Ausschnitt aus index.htmlconst express = require('express');
const url = require('url');
const bodyParser = require("body-parser");
const portnumber = 4012;
const server = express();
server.use(express.static("."));
server.use(bodyParser.urlencoded({ extended: false, limit: '1mb' }));
server.post('/submit-message', submitMessagePost);
server.listen(portnumber, function () {
console.log('listening at port ' + portnumber);
});
function submitMessagePost(req, res) {
data = req.body;
var text = `<html>n<body>n`;
for (let key in data) {
text += `<p><strong>${key}:</strong> ${data[key]}</p>n`;
}
text += `</body>n</html>n`;
res.send(text);
}
<form action="submit-message" method="POST">
<div class="form-group">
<label for="username">Benutzername:</label>
<input name="username"><br>
<textarea name="user-message"></textarea>
</div>
<button type="submit" class="btn btn-default">Submit via POST</button>
</form>
Der Unterschied im Node.js-Code ist, dass wir im ersten Fall dem
Server mit server.get (...)
mitteilen, wie er auf ein bestimmtes GET
reagieren soll, im zweiten Fall mit server.post (...)
, wie er auf einen
bestimmten POST
-Befehl reagieren soll (Zeile 10).
Der zweite Unterschied ist, dass im GET
-Fall die Daten, also
in unserem Fall unsername, user-message
, im URL selbst kodiert sind
und wir ihn mit data = url.parse(req.url, true).query;
rausziehen müssen,
während im POST
-Fall diese Daten in req.body
liegen (Zeile 16).
Zum Abschluss dieses Abschnitts schauen wir uns auch noch einmal im HTTP-Urtext an,
wie
genau
denn dieser POST-Request aussieht, den der Browser an den Server schickt.
POST /submit-message HTTP/1.1
Host: localhost:2005
Connection: keep-alive
Content-Length: 179
Cache-Control: max-age=0
sec-ch-ua: "Google Chrome";v="105", "Not)A;Brand";v="8", "Chromium";v="105"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "macOS"
Upgrade-Insecure-Requests: 1
Origin: http://localhost:2005
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://localhost:2005/
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7,de;q=0.6,da;q=0.5
username=Dominik&user-message=Dies+ist+ein+Beispieltext%2C+der+demonstrieren+soll%2C+wie+ein+POST-Request+im+Original+aussieht.%0D%0A%0D%0A-+G%C3%B6rlitz%2C+den+22.+September+2022ˇ
public_html
oder wie auch immer bedienen.
Hier ist ein Beispiel:
Der Server soll bei Anfrage auf /
oder /index.html
dynamisch eine HTML-Datei generieren, die alle Dateien im Ordner
public_html
als Liste von Links darstellt:
Darunter soll es eine Input-Maske geben, in der der User eine neue Datei hochladen kann.
Auf Knopfdruck "upload file" soll der Server eine neue Datei mit den angegebenen Dateinamen
anlegen
und den Inhalt der Text-Area in die Datei schreiben. Er soll also im Order
public_html
eine neue Datei anlegen.
Schreiben Sie mit express.js eine Anwendung, auf der mehrere Benutzer Nachrichten schreiben können, die dann einfach der Reihe nach allen angezeigt werden. Ihr Ergebnis sollte in etwa so aussehen: