From 6247bb9c2493fd4f219ee283bfc9568c1a44f87b Mon Sep 17 00:00:00 2001 From: Lukas Panni Date: Wed, 29 Nov 2023 19:55:10 +0100 Subject: [PATCH] Add HTTP Versions + Content Negotiation --- Material/Slides/01_Vorstellung_Intro.md | 12 +++- Material/Slides/02_HTTP_REST.md | 85 +++++++++++++++++++++--- Material/Slides/media/HTTP3.png | Bin 0 -> 10977 bytes 3 files changed, 88 insertions(+), 9 deletions(-) create mode 100644 Material/Slides/media/HTTP3.png diff --git a/Material/Slides/01_Vorstellung_Intro.md b/Material/Slides/01_Vorstellung_Intro.md index fc98ef8..bfac0ac 100644 --- a/Material/Slides/01_Vorstellung_Intro.md +++ b/Material/Slides/01_Vorstellung_Intro.md @@ -77,7 +77,7 @@ plantuml-format: svg ### Projektarbeit: - Entwicklung einer (kleinen) Webanwendung mit hier gelernten Technologien -- Gruppenarbeit möglich (<=4 Studierende) +- Gruppenarbeit möglich (3 - 5 Studierende) - Bewertung mit Vorlesung Projektmanagement (Hr. Merkel) - Note Webengineering: - Konzept & Umsetzung der Webanwendungen @@ -85,6 +85,16 @@ plantuml-format: svg - Regelmäßige Vorstellung aktueller Zwischenstände - Note Projektmanagement: Projektmanagement, mehr dazu von Hr. Merkel +\rightarrow{} **Aufgabe bis in 2 Wochen (22.01.): Gruppen bilden & Thema überlegen** + +## Projektarbeit - mögliche Themen + +- TODO-App +- Zeiterfassung ("Stechuhr") +- einfaches Spiel (Snake, Pac-Man, ...) +- Dashboard für Daten von einer APIs (GitHub, deps.dev, ...) + - [verschiedene Daten öffentlicher Stellen](https://github.com/bundesAPI) +- eigene Ideen # Vorlesungsinhalt & Lernziele diff --git a/Material/Slides/02_HTTP_REST.md b/Material/Slides/02_HTTP_REST.md index af12f8a..2d9b44d 100644 --- a/Material/Slides/02_HTTP_REST.md +++ b/Material/Slides/02_HTTP_REST.md @@ -27,7 +27,7 @@ plantuml-format: svg - Protokoll speichert keine Informationen! - Jedes Request-Response-Paar ist unabhängig voneinander - Erhöht Skalierbarkeit \rightarrow{} dazu später mehr - - Zustandsinformationen (z.B. Logindaten) müssen auf andere Art und Weise gespeichert werden + - ABER: Zustandsinformationen (z.B. Logindaten) müssen auf andere Art und Weise gespeichert werden ## HTTP Request - Response @@ -63,7 +63,36 @@ Date: Fri, 17 Nov 2023 12:26:59 GMT ## Verbreitung der HTTP-Versionen -![](https://blog.cloudflare.com/content/images/2023/06/download-3.png){height=95%} +![](https://blog.cloudflare.com/content/images/2023/06/download-3.png){height=80%} + +_https://blog.cloudflare.com/content/images/2023/06/download-3.png_ + +## HTTP-Versionen + +- 1996: **HTTP/1.0** +- 1999: **HTTP/1.1** + - Verschiedene Verbesserungen, z.B. Pipelining zur Reduktion von TCP-Verbindungen + - Einführung von optionalem "Host"-[[HTTP-Header|Header]] + - → ermöglicht Nutzung von einem physischen Server für mehrere Webseiten +- 2015: **HTTP/2** + - **Ziel**: Performanceverbesserungen und Optimierungen + - Volle Abwärtskompatibilität + - Multiplexing: mehrere Anfragen über eine Verbindung + - Server-initiierte Datenübertragung \rightarrow{} konnte sich nicht durchsetzen, seit Chrome 106 (September 2022) nicht mehr unterstützt + + +## HTTP-Versionen + +- 2022: **HTTP/3** + - Neues Übertragungsprotokoll: **QUIC** + - Bei zuvor genutztem Multiplexing über TCP ist Head-of-Line-Blocking möglicht + - Bei Paketverlust müssen alle folgenden Pakete (aller gemultiplexten Streams) auf erneute Übertragung des Verlorenen warten + - Mehrere nutzt _unabhängige_ parallele Datenströme über UDP, Head-of-Line-Blocking betrifft jeweils nur einen Stream + +## HTTP-Versionen - HTTP/3 vs. HTTP/2 +![](media/HTTP3.png){height=65%} + +_https://de.wikipedia.org/wiki/Hypertext_Transfer_Protocol#/media/Datei:HTTP-2_vs._HTTP-3_Protocol_Stack.svg_ ## HTTP Header @@ -78,19 +107,59 @@ Date: Fri, 17 Nov 2023 12:26:59 GMT - Accept-Language - Cookie - ... +- Steuern verschiedene Funktionen ... -## Exkurs HTTP Content Negotiation +## HTTP Content Negotiation - Feature das eine *automatische* Einigung auf ein Ausgabeformt ermöglicht -- Client sendet gewünschtes Format im `Accept`-Header +- Ermöglicht verschiedene _Repräsentationen_ für die gleiche _Ressource_ +- Weitere Header für Sprache (`Accept-Language`) und Kodierung `Accept-Encoding` +- Format der Antwort über `ContentType`, `Language`, `Encoding` Header angegeben + +- Server-driven (Server entscheidet): + - Client sendet gewünschtes Format im `Accept`-Header - Angabe mehrerer Formate: z.B. `Accept: text/html,text/plain` - Server gibt die Antwort im ersten untertützten Format zurück -- Format der Antwort über `ContentType`-Header angegeben -```{.plantuml height=35%} -Client->Server : Accept: application/json, text/xml -Server->Client : ContentType: application/json + +## HTTP Content Negotiation + +```{.plantuml height=50%} +Client->Server : GET /; Accept: application/json, text/xml +Server->Client : 200 OK, ContentType: application/json ``` +## HTTP Content Negotiation + +- Agent-driven (Client entscheidet) + - Gleicher Beginn, Server antwortet mit Liste verfügbarer Repräsentationen + - Client kann die am besten passende auswählen und anfragen + + +```{.plantuml height=50%} +Client->Server : GET /; Accept: application/json, text/xml +Server->Client : 300 Multiple Choices; ... +Client->Server : GET /r1; Accept: application/json +Server->Client : 200 OK, ContentType: application/json +``` + + +## HTTP Content Negotiation + +- Beide Varianten haben Vor- und Nachteile + +| | Nachteile | Vorteile | +| --- | --- | --- | +| Server-driven | gute Unterstzützung | Server kann nicht optimal entscheiden | +| Agent-driven | kein einheitliches Format | - Client kann die optimale Entscheidung treffen \newline - zusätzlicher Request notwendig | + + + + +## HTTP Methoden + + +## HTTP Status Codes + # REST diff --git a/Material/Slides/media/HTTP3.png b/Material/Slides/media/HTTP3.png new file mode 100644 index 0000000000000000000000000000000000000000..45196a82789eb56e20454eb4907fc334fb85466a GIT binary patch literal 10977 zcmaKSbyQnH_iai`DNvw=mKHDW?%q<0OK}ep+}))VEAH+Rq`13VA-Dy%5Zo;|FW>sT zf4=o(WhHa&&6=4zGkeb6XP*iEsUV4kL5KkW0I;N`#FdfdGV*)z<~8#7D97ChS-dj) zCjSipsE)>bFhoUOe*sA;%L4$OGyuS_KmgzldF$6M0N}y~0PGt800Johz$g2R79}C% zAFqvMCB*^H|M}#!7sUer^f%Jt-&EZfk5=5is=>(y&k!WK*Q6*EbQF2N@o0~QiN=PP z86{0SncOVEU>>PHU(_`VE8985m|2lMNMj+5!@Cd{>uI}%mow91PoJ2Bq zgm#vlKA^)UDFf+nEdi9zKssw(Fi#+zxCL6LqS{O3m6CvZ0^$3-pY&HUC9lZC*c_En z#iZ5)W4h4EsqFt_y~E}EZ|eBQ{s%fjl*iWU#!B zd(iQN1)r+r{P|o86tPuhz31vM4^t^}#trouiLyk+LZLXWl?UPP#ll(pF zx(IY(b&L-qdn*jRKF*pD@r;t}GQz(NuFP89d`TQ=t-Cdve3AppQ<@&73)h z;qkvdbTj0Gh|5FsFLuOv6td z`I0uEct?X&hmo^a=p=aX^uB^qe4tNdZYa2-+=}q&Otxb7-9z^0~MsLh3^3GU$n!}B^K^;(+a(16?(qKiknka^EtiX)W2Q_Ur; zO@NPRM6M}3g63d7T79Y{m6eudxzJk+ElRJc zKjAiAljBOBX7v80A}?B0X6I<#NrU5l<5_}B&5L!vT0gVtCrqx3%D`#~d5FJL%HwM3 z+mqRus>7#vzdTtd(J>%;cYc|$
    Fz8$ZV2P|Y>E4|wMD4SS_AYroP@=;xtfm$!^ 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 literal 0 HcmV?d00001