Webtechnologien
Wintersemester 2024
Express.js
♯
♫
Express.js
<section bg="express-cover.jpg" class="slide cover"><div><h2> </h2> </div></section> <section class="slide" id="express"><div><h2><a href="https://expressjs.com/de/">Express</a></h2> <ul> <li>Populärstes Web-Framework für Node.js</li> </ul> <pre class="highlight language-js" data-lang="js"><code><span class="k">import</span> <span class="nx">express</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">express</span><span class="dl">'</span><span class="p">;</span> <span class="kd">const</span> <span class="nx">app</span> <span class="o">=</span> <span class="nf">express</span><span class="p">();</span> <span class="nx">app</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="dl">'</span><span class="s1">/</span><span class="dl">'</span><span class="p">,</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span> <span class="c1">// app.METHOD(PATH, HANDLER)</span> <span class="nx">res</span><span class="p">.</span><span class="nf">send</span><span class="p">(</span><span class="dl">'</span><span class="s1">Hello World!</span><span class="dl">'</span><span class="p">);</span> <span class="p">});</span> <span class="nx">app</span><span class="p">.</span><span class="nf">listen</span><span class="p">(</span><span class="mi">3000</span><span class="p">,</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span> <span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">Example app listening on port 3000!</span><span class="dl">'</span><span class="p">);</span> <span class="p">});</span> </code></pre> <footer> <ul> <li>erleichtert den Umgang mit Node.js HTTP und beschleunigt dadurch die Entwicklung</li> <li><code class="language-plaintext highlighter-rouge">app</code>-Object das verschiedene Funktionen bereit stellt</li> <li>reichhaltiges Öko-System</li> </ul> </footer> </div></section> <section class="slide" id="query-parameter"><div><h2>Query-Parameter</h2> <pre class="highlight language-js" data-lang="js"><code><span class="k">import</span> <span class="nx">express</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">express</span><span class="dl">'</span><span class="p">;</span> <span class="kd">const</span> <span class="nx">app</span> <span class="o">=</span> <span class="nf">express</span><span class="p">();</span> <span class="c1">// GET /search?q=immobilienkredite</span> <span class="nx">app</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="dl">'</span><span class="s1">/search</span><span class="dl">'</span><span class="p">,</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span> <span class="nx">res</span><span class="p">.</span><span class="nf">send</span><span class="p">(</span><span class="s2">`You searched for: </span><span class="p">${</span><span class="nx">req</span><span class="p">.</span><span class="nx">query</span><span class="p">.</span><span class="nx">q</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span> <span class="p">});</span> <span class="nx">app</span><span class="p">.</span><span class="nf">listen</span><span class="p">(</span><span class="mi">3000</span><span class="p">,</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span> <span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">Example app listening on port 3000!</span><span class="dl">'</span><span class="p">);</span> <span class="p">});</span> </code></pre> <footer> <ul> <li><code class="language-plaintext highlighter-rouge">nodemon</code> vorstellen</li> </ul> </footer> </div></section> <section class="slide" id="middlewares"><div><h2>Middlewares</h2> <pre class="highlight language-js" data-lang="js"><code><span class="nx">app</span><span class="p">.</span><span class="nf">use</span><span class="p">((</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">,</span> <span class="nx">next</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span> <span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">before</span><span class="dl">'</span><span class="p">);</span> <span class="nf">next</span><span class="p">();</span> <span class="p">});</span> <span class="nx">app</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="dl">'</span><span class="s1">/</span><span class="dl">'</span><span class="p">,</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">,</span> <span class="nx">next</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span> <span class="nx">res</span><span class="p">.</span><span class="nf">send</span><span class="p">(</span><span class="dl">'</span><span class="s1">Hello</span><span class="dl">'</span><span class="p">);</span> <span class="nf">next</span><span class="p">();</span> <span class="p">});</span> <span class="nx">app</span><span class="p">.</span><span class="nf">use</span><span class="p">((</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">,</span> <span class="nx">next</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span> <span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">after</span><span class="dl">'</span><span class="p">);</span> <span class="nf">next</span><span class="p">();</span> <span class="p">});</span> </code></pre> <footer> <ul> <li>mächtiges Werkzeug: Middlewares</li> <li>Middleware: Funktionen die bei Ein- und Austritt durchlaufen werden</li> <li>Request-Handler: <code class="language-plaintext highlighter-rouge">request</code>, <code class="language-plaintext highlighter-rouge">response</code>, <code class="language-plaintext highlighter-rouge">next</code></li> </ul> </footer> </div></section> <section class="slide" id="middleware-beispiel"><div><h2>Middleware Beispiel</h2> <pre class="highlight language-js" data-lang="js"><code><span class="k">import</span> <span class="nx">express</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">express</span><span class="dl">'</span><span class="p">;</span> <span class="kd">const</span> <span class="nx">app</span> <span class="o">=</span> <span class="nf">express</span><span class="p">();</span> <span class="kd">const</span> <span class="nx">requestTime</span> <span class="o">=</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">,</span> <span class="nx">next</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span> <span class="nx">req</span><span class="p">.</span><span class="nx">requestTime</span> <span class="o">=</span> <span class="nb">Date</span><span class="p">.</span><span class="nf">now</span><span class="p">();</span> <span class="nf">next</span><span class="p">();</span> <span class="p">};</span> <span class="nx">app</span><span class="p">.</span><span class="nf">use</span><span class="p">(</span><span class="nx">requestTime</span><span class="p">);</span> <span class="nx">app</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="dl">'</span><span class="s1">/</span><span class="dl">'</span><span class="p">,</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span> <span class="nx">res</span><span class="p">.</span><span class="nf">send</span><span class="p">(</span><span class="s2">`Page requested at </span><span class="p">${</span><span class="nx">req</span><span class="p">.</span><span class="nx">requestTime</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span> <span class="p">});</span> <span class="nx">app</span><span class="p">.</span><span class="nf">listen</span><span class="p">(</span><span class="mi">3000</span><span class="p">);</span> </code></pre> <footer> <ul> <li>das Beispiel fügt jedem Request eine Uhrzeit bei</li> <li>Beispiel umbauen <ul> <li>Zeit zur Erzeugung der Antwort berechnen</li> </ul> </li> </ul> </footer> </div></section> <section class="slide" id="statische-dateien"><div><h2>Statische Dateien</h2> <ul> <li>Middleware <code class="language-plaintext highlighter-rouge">static</code> liefert statische Dateien aus</li> </ul> <pre class="highlight language-js" data-lang="js"><code><span class="nx">app</span><span class="p">.</span><span class="nf">use</span><span class="p">(</span><span class="nx">express</span><span class="p">.</span><span class="nf">static</span><span class="p">(</span><span class="dl">'</span><span class="s1">public</span><span class="dl">'</span><span class="p">));</span> </code></pre> <pre class="highlight language-sh" data-lang="sh"><code><span class="nb">touch </span>public/styles.css </code></pre> <pre class="highlight language-html" data-lang="html"><code><span class="nt"><link</span> <span class="na">rel=</span><span class="s">"stylesheet"</span> <span class="na">href=</span><span class="s">"/styles.css"</span><span class="nt">></span> </code></pre> <footer> <ul> <li>noch mal: es geht in dieser Schulung nicht um Node, sondern um Web-Technologien – was wir uns anschauen, lässt sich auch auf andere Sprachen übertragen</li> <li>integrierte Middleware: <code class="language-plaintext highlighter-rouge">static</code> liefert Dateien aus</li> </ul> </footer> </div></section> <section class="slide" id="templates"><div><h2>Templates</h2> <pre class="highlight language-js" data-lang="js"><code><span class="nx">app</span><span class="p">.</span><span class="nf">set</span><span class="p">(</span><span class="dl">'</span><span class="s1">view engine</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">ejs</span><span class="dl">'</span><span class="p">);</span> <span class="c1">// views sind vom typ "ejs"</span> <span class="nx">app</span><span class="p">.</span><span class="nf">set</span><span class="p">(</span><span class="dl">'</span><span class="s1">views</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">views</span><span class="dl">'</span><span class="p">);</span> <span class="c1">// … und liegen im ordner "views" (default)</span> <span class="c1">// render "views/profile.ejs" mit daten aus `user`</span> <span class="nx">res</span><span class="p">.</span><span class="nf">render</span><span class="p">(</span><span class="dl">'</span><span class="s1">profile</span><span class="dl">'</span><span class="p">,</span> <span class="p">{</span> <span class="na">user</span><span class="p">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">user</span> <span class="p">});</span> </code></pre> <pre class="highlight language-html" data-lang="html"><code><span class="nt"><h1></span>Hallo <span class="nt"><</span><span class="err">%=</span> <span class="na">user.name</span> <span class="err">%</span><span class="nt">></h1></span> </code></pre> <ul> <li>default Engine: <a href="https://ejs.co/">EJS</a></li> <li>es gibt aber <a href="https://expressjs.com/en/resources/template-engines.html">viele viele mehr</a></li> </ul> <footer> <ul> <li>Trennung von Geschäftslogik und Präsentation</li> <li>HTML mit eingebetteten Datenfeldern und ein paar Kontrollstrukturen</li> <li>Aufgaben: <ul> <li>Darstellung von Variablen</li> <li>Kontrollstrukturen (if, else)</li> <li>Iteration (for each)</li> <li>Sicherheit: automatisches Escaping (kommen wir gleich zu)</li> </ul> </li> <li>viele Umsetzungen: EJS (default), Pug, Handlebars, Hogan</li> </ul> </footer> </div></section> <section class="slide" id="formulare"><div><h2>Formulare</h2> <pre class="highlight language-js" data-lang="js"><code><span class="k">import</span> <span class="nx">bodyParser</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">body-parser</span><span class="dl">'</span><span class="p">;</span> <span class="c1">// für `application/x-www-form-urlencoded` (normale formulare)</span> <span class="nx">app</span><span class="p">.</span><span class="nf">use</span><span class="p">(</span><span class="nx">bodyParser</span><span class="p">.</span><span class="nf">urlencoded</span><span class="p">({</span> <span class="na">extended</span><span class="p">:</span> <span class="kc">false</span> <span class="p">}));</span> <span class="c1">// für `application/json` (später wichtig für ajax-zeugs)</span> <span class="nx">app</span><span class="p">.</span><span class="nf">use</span><span class="p">(</span><span class="nx">bodyParser</span><span class="p">.</span><span class="nf">json</span><span class="p">());</span> <span class="nx">app</span><span class="p">.</span><span class="nf">post</span><span class="p">(</span><span class="dl">'</span><span class="s1">/login</span><span class="dl">'</span><span class="p">,</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span> <span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">username</span><span class="p">,</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">password</span><span class="p">);</span> <span class="p">});</span> </code></pre> <footer> <ul> <li>parsed übermittelte formulardaten und macht sie unter <code class="language-plaintext highlighter-rouge">req.body</code> verfügbar</li> <li>niemals trauen! all user input is evil!</li> </ul> </footer> </div></section> <section class="slide" id="validierung-von-formulardaten"><div><h2>Validierung von Formulardaten</h2> <ul> <li>Validation: Prüfen auf bestimmte Muster hin (✔)</li> <li>Sanitization: Bereinigen um bestimmte Zeichen (✗)</li> <li>Escaping: Umwandeln von Zeichen in andere Darstellungsform (✔)</li> <li><a href="https://github.com/validatorjs/validator.js">validator.js</a></li> <li><a href="https://github.com/sideway/joi">Joi</a></li> <li><a href="https://github.com/minimaxir/big-list-of-naughty-strings">Big List of Naughty Strings</a></li> <li><a href="https://github.com/cure53/DOMPurify">DOMPurify</a></li> </ul> <footer> <ul> <li>Validierung: Validierung ist der Prozess der Sicherstellung, dass gegebene Eingabedaten in den Bereich der gültigen Eingabewerte fallen.</li> <li>Leicht falsch zu machen, schwer richtig, und nie mit Gewissheit.</li> <li>Sanitization (filtering, cleaning): Entfernen von potentiell gefährlichen Zeichen <ul> <li>warum? Was ist das Ziel?</li> <li>Namen lassen sich quasi nicht validieren (zu kurz? <code class="language-plaintext highlighter-rouge">Li</code>; keine Zahlen? <code class="language-plaintext highlighter-rouge">George III</code>, nur ASCII? <code class="language-plaintext highlighter-rouge">René Šliževičiūtė</code>)</li> <li>E-Mails lassen sich nur durch Versand eines Links validieren, alles andere ist zu kurz gedacht</li> </ul> </li> <li>Escaping: Umwandeln von potentiell gefährlichen Zeichen in andere Darstellungsform</li> <li>Escape-on-Input vs Escape-on-Output <ul> <li>Ist <code class="language-plaintext highlighter-rouge"><script>alert(1)</script></code> ein valider Benutzername? Ist <code class="language-plaintext highlighter-rouge">"; drop table users;--</code> ein valider Suchbegriff? Risiko von Fehler in Presentation-Layer an einer Stelle vs. Double-Escaping</li> <li>Antwort: On Output. Weil <ul> <li>a) unterschiedliche Ziel-Umgebungen, z.B. HTML, JSON, URL, PDF, Excel und</li> <li>b) sonst intern falsche Darstellung (suche nach <code class="language-plaintext highlighter-rouge">amp</code> findet <code class="language-plaintext highlighter-rouge">&</code>)</li> <li>HTML: <code class="language-plaintext highlighter-rouge">‘ < > </q> &</code></li> <li>URLs: <code class="language-plaintext highlighter-rouge">/ : & ? #</code>, text starting with <code class="language-plaintext highlighter-rouge">javascript:</code></li> <li>Javascript: <code class="language-plaintext highlighter-rouge"></q> ‘</code></li> <li>SQL: <code class="language-plaintext highlighter-rouge">‘</code></li> <li>JSON: <code class="language-plaintext highlighter-rouge"><q></code></li> </ul> </li> <li>Noch schwieriger, wenn eins in anderem enbedded</li> </ul> </li> <li>immer im Backend!</li> <li>Zusammenfassung: Validierung aller Inputs und Escaping aller Outputs vor Darstellung</li> <li>Express escaped automatisch</li> </ul> </footer> </div></section> <section class="slide" id="cookies"><div><h2>Cookies</h2> <pre class="highlight language-js" data-lang="js"><code><span class="k">import</span> <span class="nx">cookieParser</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">cookie-parser</span><span class="dl">'</span><span class="p">;</span> <span class="nx">app</span><span class="p">.</span><span class="nf">use</span><span class="p">(</span><span class="nf">cookieParser</span><span class="p">());</span> <span class="nx">app</span><span class="p">.</span><span class="nf">use</span><span class="p">((</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">,</span> <span class="nx">next</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span> <span class="nx">req</span><span class="p">.</span><span class="nx">trackingId</span> <span class="o">=</span> <span class="nx">req</span><span class="p">.</span><span class="nx">cookies</span><span class="p">.</span><span class="nx">trackingId</span><span class="p">;</span> <span class="k">if </span><span class="p">(</span><span class="o">!</span><span class="nx">req</span><span class="p">.</span><span class="nx">trackingId</span><span class="p">)</span> <span class="p">{</span> <span class="kd">const</span> <span class="nx">trackingId</span> <span class="o">=</span> <span class="nb">Date</span><span class="p">.</span><span class="nf">now</span><span class="p">().</span><span class="nf">toString</span><span class="p">(</span><span class="mi">32</span><span class="p">);</span> <span class="nx">res</span><span class="p">.</span><span class="nf">cookie</span><span class="p">(</span><span class="dl">'</span><span class="s1">trackingId</span><span class="dl">'</span><span class="p">,</span> <span class="nx">trackingId</span><span class="p">);</span> <span class="nx">req</span><span class="p">.</span><span class="nx">trackingId</span> <span class="o">=</span> <span class="nx">trackingId</span><span class="p">;</span> <span class="p">}</span> <span class="nf">next</span><span class="p">();</span> <span class="p">});</span> </code></pre> <footer> <ul> <li>schauen wir uns auch Drittanbieter-Middlewares an: <ul> <li><code class="language-plaintext highlighter-rouge">cookie-parser</code> (können auch direkt aus HTTP-Header ausgelesen werden, aber so viel leichter)</li> <li><code class="language-plaintext highlighter-rouge">body-parser</code> für Body (e.g. Formulardaten)</li> </ul> </li> <li>Beispiel: Tracking / Wiedererkennen von Besuchern (z.B. zur Analyse von User-Flows)</li> </ul> </footer> </div></section> <section class="slide" id="signed-cookies"><div><h2>Signed Cookies</h2> <ul> <li>Signiert (HMAC), nicht verschlüsselt</li> </ul> <pre class="highlight language-js" data-lang="js"><code><span class="k">import</span> <span class="nx">cookieParser</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">cookie-parser</span><span class="dl">'</span><span class="p">;</span> <span class="nx">app</span><span class="p">.</span><span class="nf">use</span><span class="p">(</span><span class="nf">cookieParser</span><span class="p">(</span><span class="dl">'</span><span class="s1">ein geheimnis</span><span class="dl">'</span><span class="p">));</span> <span class="c1">// geheimnis definieren</span> <span class="nx">res</span><span class="p">.</span><span class="nf">cookie</span><span class="p">(</span><span class="dl">'</span><span class="s1">key</span><span class="dl">'</span><span class="p">,</span> <span class="nx">value</span><span class="p">,</span> <span class="p">{</span> <span class="na">signed</span><span class="p">:</span> <span class="kc">true</span> <span class="p">});</span> <span class="c1">// cookies signiert setzen</span> <span class="kd">const</span> <span class="p">{</span> <span class="nx">value</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">req</span><span class="p">.</span><span class="nx">signedCookies</span><span class="p">;</span> <span class="c1">// signierte cookies auslesen</span> </code></pre> <footer> <ul> <li>man sollte nie im klartext daten in cookies speichern, weil diese verändert werden können</li> <li>signierung: folgender wert ist garantiert von uns geschrieben; aber wert ist offen lesbar</li> <li>https://github.com/tj/node-cookie-signature/blob/master/index.js#L19</li> </ul> </footer> </div></section> <section class="slide" id="benutzerverwaltung"><div><h2>Benutzerverwaltung</h2> <pre class="highlight language-js" data-lang="js"><code><span class="k">import</span> <span class="o">*</span> <span class="nx">as</span> <span class="nx">argon2</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">argon2</span><span class="dl">"</span><span class="p">;</span> <span class="nx">app</span><span class="p">.</span><span class="nf">post</span><span class="p">(</span><span class="dl">'</span><span class="s1">/register</span><span class="dl">'</span><span class="p">,</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span> <span class="nx">argon2</span><span class="p">.</span><span class="nf">hash</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">password</span><span class="p">).</span><span class="nf">then</span><span class="p">((</span><span class="nx">hash</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span> <span class="nf">addUser</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">email</span><span class="p">,</span> <span class="nx">hash</span><span class="p">);</span> <span class="nx">res</span><span class="p">.</span><span class="nf">redirect</span><span class="p">(</span><span class="dl">'</span><span class="s1">/login</span><span class="dl">'</span><span class="p">);</span> <span class="p">})});</span> <span class="nx">app</span><span class="p">.</span><span class="nf">post</span><span class="p">(</span><span class="dl">'</span><span class="s1">/login</span><span class="dl">'</span><span class="p">,</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span> <span class="nx">argon2</span><span class="p">.</span><span class="nf">verify</span><span class="p">(</span><span class="nf">getUser</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">email</span><span class="p">).</span><span class="nx">hash</span><span class="p">,</span> <span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">password</span><span class="p">)</span> <span class="p">.</span><span class="nf">then</span><span class="p">(()</span> <span class="o">=></span> <span class="p">{</span> <span class="c1">// ✅ korrektes Passwort</span> <span class="kd">const</span> <span class="nx">session</span> <span class="o">=</span> <span class="nf">generateToken</span><span class="p">();</span> <span class="nf">addSession</span><span class="p">(</span><span class="nx">session</span><span class="p">,</span> <span class="nx">email</span><span class="p">);</span> <span class="nx">res</span><span class="p">.</span><span class="nf">cookie</span><span class="p">(</span><span class="dl">'</span><span class="s1">session</span><span class="dl">'</span><span class="p">,</span> <span class="nx">session</span><span class="p">,</span> <span class="p">{</span> <span class="na">httpOnly</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span> <span class="na">secure</span><span class="p">:</span> <span class="kc">true</span> <span class="p">});</span> <span class="k">return</span> <span class="nx">res</span><span class="p">.</span><span class="nf">redirect</span><span class="p">(</span><span class="dl">'</span><span class="s1">/</span><span class="dl">'</span><span class="p">);</span> <span class="p">}).</span><span class="k">catch</span><span class="p">(()</span> <span class="o">=></span> <span class="p">{</span> <span class="c1">// ❌ falsches Passwort</span> <span class="nx">res</span><span class="p">.</span><span class="nf">sendStatus</span><span class="p">(</span><span class="mi">401</span><span class="p">);</span> <span class="p">});</span> <span class="p">});</span> </code></pre> </div></section> <section class="slide" id="link"><div><h2>Link</h2> <ul> <li><a href="https://nodejs.dev/">Introduction to Node.js</a></li> <li><a href="https://github.com/i0natan/nodebestpractices#readme">The largest Node.js best practices list</a></li> </ul> </div></section>