3. Interaktion mit dem Server
3.3 HTTP: Mit einem Webserver kommunizieren
Versuchen wir nun, mit einem Webserver zu kommunizieren. Stark reduziert funktioniert die Kommunikation zwischen dem Web-Client (meistens ein Browser) und dem Server so: der Client sagt "schick mir bitte Datei X", und der Web-Server schickt X. Arbeiten wir uns langsam vor. Bauen wir eine Verbindung mit dem Webserver web1.hszg.de auf.
telnet web1.hszg.de 1234 # auf windows
nc web1.hszg.de 1234 # auf OSX
java MyTelnet web1.hszg.de 1234 # alternativ, auf beiden Platformen
Ich werde jetzt mein selbst geschriebenes MyTelnet.java verwenden, der deutlicheren Fehlermeldungen wegen:
java MyTelnet web1.hszg.de 1234
Exception in thread "main" java.net.ConnectException: Connection refused
Der Fehler kommt daher, da auf web1.hszg.de
einfach kein Prozess läuft, der auf Port
1234 Verbindungen entgegennimmt
("lauscht"). Kein Wunder. Um einen Server zu finden, brauchen wir den Namen / die IP-Adresse
des Rechners (hier also web1.hszg.de) und die Portnummer. Typischerweise
haben bestimmte Protokolle feste Portnummern. HTTP verwendet Port 80. Also:
java MyTelnet web1.hszg.de 80
|
Jetzt kommt keine Fehlermeldung mehr, allerdings auch keine Nachricht. Wir haben nun auf Port 80 einen Server erwischt. Schicken wir ihm doch ein paar Bytes!
java MyTelnet web1.hszg.de 80
Hallo! Ist da wer?
HTTP/1.1 400 Bad Request Date: Fri, 28 Oct 2022 12:39:34 GMT Server: Apache Content-Length: 347 Connection: close Content-Type: text/html; charset=iso-8859-1 <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>400 Bad Request</title> </head><body> <h1>Bad Request</h1> <p>Your browser sent a request that this server could not understand.<br /> </p> <p>Additionally, a 400 Bad Request error was encountered while trying to use an ErrorDocument to handle the request.</p> </body></html>
Aha. Auf Port 80 lauscht tatsächlich ein Server, der auch tatsächlich antwortet, wenn auch nur "Ich verstehe nicht, was Du sagst". Aber sehen Sie sich die Antwort an: nach den ersten sechs Zeilen folgt eine Leerzeile, und dann sehen wir HTML-Code! Der Server schickt uns offensichtlich eine HTML-Datei.
Bitte beachten Sie den Unterschied: der Aufruf java MyTelnet web1.hszg.de 1234
erzeugte
eine
Exception in unserem Java-Code; bereits der Aufbau der TCP-Verbindung ist gescheitert.
Der zweite Versuch, java MyTelnet web1.hszg.de 80
, ist aus Sicht von TCP
erfolgreich:
es wurde eine Verbindung aufgebaut und Daten ausgetauscht. Die Antwort des Servers,
... 400 Bad Request ist zwar auch eine Fehlermeldung, allerdings kein TCP-Fehler,
sondern ein Was-auch-immer-der-Server-erwartet-Fehler.
Akt 1: Browser mit http-server
Es ist für Erste einfacher, wenn wir mit einem Webserver kommunizieren, der
direkt auf unserem Rechner läuft. Start wir also einen. Dies haben Sie in den obigen
Übungen bereits getan. Öffnen Sie ein Terminal, hehen Sie in das Verzeichnis, in welchem Ihre
Version von
example.html
liegt, und starten
http-server . -p 8080
Jetzt öffnen Sie einen Browser und geben in der Adresszeile
localhost:8080/example.html
ein. Bei mir sieht das Ergebnis so aus:
Wir hätten genausogut die Datei direkt mit dem Browser öffnen können. Das Ergebnis wäre das gleiche. Allerdings passiert hier konzeptuell viel mehr: der Browser (in meinem Screenshot: Safari) versucht, eine TCP-Verbindung zum Rechner localhost auf Port 8080 aufzubauen. Dort lauscht gerade tatsächlich ein Server (hier: http-server). Der Browser schickt nun über die jetzt etablierte TCP-Verbindung etwas an den Server, das diesen offensichtlich dazu veranlasst, ihm etwas zu schicken, das mit example.html zu tun hat.
Akt 2: Browser mit Terminal-Server OnePersonServer
Um rauszufinden, was der Browser an den Serer geschickt hat, beenden wir den
http-server (gehen auf das Terminal und drücken Ctrl+C).
Dann starten wir OnePersonServer.java
und spielen jetzt "Server von Hand" auf Port 8080. Geben Sie also auf einem Terminal
java OnePersonServer 8080
ein. Gehen Sie
dann in den Browser, öffen ein neues Tab und geben dort noch einmal
localhost:8080/example.html
ein. Drücken Sie ENTER. Der Browser
sollte nun nichts anzeigen, sondern "hängen". Eventuell
liegt example.html
noch im Browser-Cache und wird korrekt angezeigt; das hängt
vom Browser ab. Versuchen Sie, die Seite neu zu laden, sie in einem neuen Tab zu öffnen oder,
falls sie daan immer noch korrekt angezeigt wird, Ihren Browser-Cache zu löschen.
Wenn der Browser die Seite nicht mehr anzeigt, sondern hängt, hat es geklappt.
Gehen Sie jetzt auf das Terminal, wo
OnePersonServer.java
läuft.
Sie sollten in etwa so etwas sehen:
java OnePersonServer 8080
GET /example.html HTTP/1.1 Host: localhost:8080 Upgrade-Insecure-Requests: 1 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1.1 Safari/605.1.15 Accept-Language: en-us Accept-Encoding: gzip, deflate Connection: keep-alive
Hier sehen Sie also, wie der Browser zum Webserver spricht (in diesem Falle: zu sprechen glaubt; er spricht ja mit uns, bzw. mit OnePersonServer.java. Was Sie hier sehen, ist ein GET-Request. Das Schlüsselwort GET ist, wie bei unserem MessageServer.java, im Protokoll definiert.
Akt 3: Terminal-Client nc / telnet mit echtem Server http-server und handgeschriebenem GET-Request
In Akt 2 konnten wir lesen, welche Daten
den Browser an den Server schickt, wenn er versucht, eine Seite
zu laden. In Akt 1 konnten wir das Ergebnis sehen:
der Browser zeigt die Webseite an.
Nun, im dritten Akt, werden wir herausfinden, was denn der Server antwortet.
Das tun wir, in dem wir nun vom Terminal aus per nc (telnet, MyTelnet.java) Browser spielen.
Beenden Sie
OnePersonServer.java
und starten wieder
http-server . -p 8080
(natürlich in dem
Verzeichnis, wo example.html
liegt). Dann
verbinden wir uns mit telnet (oder nc oder
MyTelnet.java):
nc localhost 8080
und copy-pasten den GET-Request aus
Akt 2 (blauer Text) in das Terminal.
Achten Sie, dass der Text von mindestens zwei Leerzeilen gefolgt wird. Diese zeigen
nämlich dem Webserver, dass Ihr Request nun zu Ende ist.
java MySslTelnet web1.hszg.de 443
GET /scheder-lehre/WE-I/sessions/03/example.html HTTP/1.1 host: web1.hszg.deHTTP/1.1 200 OK Date: Mon, 07 Nov 2022 13:11:59 GMT Server: Apache Last-Modified: Mon, 07 Nov 2022 13:10:31 GMT ETag: "ee-5ece125edecf9" Accept-Ranges: bytes Content-Length: 238 Content-Type: text/html <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> </head> <body> Dies ist nur eine <em>Beispielseite</em> für die Kommunikation zwischen Browser und Webserver. </body> </html>
Sehr schön. Sie sehen hier in Blau einen HTTP-Response. Lesen Sie sich in Ruhe alles durch. Nicht alles ist für uns wichtig. Ich werde nun ein paar Zeilen näher besprechen:
- Die ersten beiden Zeilen im GET-Request, also
GET /scheder-lehre/WE-I/sessions/03/example.html HTTP/1.1 host: web1.hszg.de
sind obligatorisch.GET
zeigt an, dass der Browser eine "Resource" bekommen wollen (meist eine Datei); das/example.html
ist dann der Name der gewünschten Resource;HTTP/1.1
zeigt die Version des HTTP-Protokols an, die der Browser "spricht". Die zweite Zeile wiederholt nochmal Hostname und Portnummer. -
Im Response sind für uns erst einmal zwei Zeilen wichtig.
HTTP/1.1 200 OK
zeigt uns wieder die HTTP-Version an und dann den "Code" des Responses, zusammen mit dem Englischen Namen des Codes. 200 bedeutet also "Erfolg". Weiter oben haben Sie auch den Code400 Bad Request
gesehen. Wahrscheinlich ist Ihnen auch404 Not Found
schon einmal begegnet.
Akt 4: Browser mit Terminal-Server OnePersonServer mit handgeschriebenem Response
Wir wiederholen nun Akt 2. Wir starten
OnePersonServer.java,
rufen im Browser den URL
localhost:8080/example-2.html
auf (die Datei gibt es nicht, es kann uns
also nicht der Cache dazwischenfunken) und copy-pasten in dem Terminal,
wo OnePersonServer
läuft, den obigen HTTP-Response rein.
Ich "bereinige" ihn ein wenig, damit es übersichtlicher wird.
java OnePersonServer 8080
# geben Sie nun localhost:8080/example-2.html in die Adresszeile Ihres Browsers ein
GET /example-2.html HTTP/1.1 Host: localhost:8080 Upgrade-Insecure-Requests: 1 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1.1 Safari/605.1.15 Accept-Language: en-us Accept-Encoding: gzip, deflate Connection: keep-alive
HTTP/1.1 200 OK content-type: text/html; charset=UTF-8 <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> </head> <body> Dies ist ein HTTP-Response, den wir <em>per Hand</em> auf dem Terminal in unseren <code>OnePersonServer</code> eingegeben haben. </body> </html>
Achten Sie darauf, dass Sie nach <html>
eine Leerzeile einfügen.
Je nach Browser wird bereits jetzt die Webseite angezeigt (bei mir zum Beispiel mit Chrome);
eventuell wartet Ihr Browser darauf, dass der Server die Verbindung beendet (das macht Safari
bei mir); drücken Sie
Ctrl+D auf der Konsole von OnePersonServer
, dann ist die Verbindung zu,
der Browser merkt, dass nichts mehr kommt und zeigt die Seite an.
content-type: text/html; charset=UTF-8
weg.
Wie verändert das die Darstellung im Browser?
Akt 5: Kommunikation mit einem echten Server
In Akt 3 haben wir vom Terminal aus Browser gespielt und einem Webserver tatsächlich den Quellcode einer HTML-Seite "entlocken" können. In Akt 4 haben wir auf dem Terminal Webserver gespielt und einen Browser dazu gebracht, den von uns per Hand eingetippten HTML-Text auch anzuzeigen. Versuchen wir nun noch alles einmal mit einem echten Server, also einem, den wir nicht extra auf unserem Rechner gestartet haben. Zum Beispiel mit web1.hszg.de
web1.hszg.de
die Resource (d.h.: Datei)
die Datei web1.hszg.de/scheder-lehre/WE-I/WE-I.css
anfordert.
Schreiben Sie Ihren Request in eine Textdatei.
Verbinden Sie sich per telnet web1.hszg.de 80
und verschicken Sie
den Request. Funktioniert das oder geht es schief? Was würden Sie als Erfolg werten?
Je nachdem, ob die Windows oder Unix/OSX verwenden, werden Sie auf
mehrere Problem stoßen (wenn Sie MAC-User sind, kontaktieren Sie mich).
Wenn Sie die gelöst haben, bekommen Sie zwar vom Server
eine Antwort. Die sagt aber nur, dass das gesuchte Dokument
"umgezogen" ist (The document has moved ...
).
Der Grund dafür ist einfach: die allermeisten Server verwenden nicht HTTP sondern
HTTPS. Dies ist im Prinzip das gleiche wie HTTP, nur dass es "weiter unten" im
System die Daten verschlüsselt verschickt. Für uns als Anwender ändert nur wenig:
als Port verwenden es 443 und nicht mehr 80; leider können wir, soweit ich
das überblicke, telnet und nc nicht mehr verwenden. Ich habe dafür das
Java-Programm MySslTelnet.java
geschrieben.
java MySslTelnet web1.hszg.de 443
.
Sie sollten schaffen, dem Server die tatsächliche Datei zu entlocken.