<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>webdienst Archive - Robert Skibbe</title>
	<atom:link href="https://robbelroot.de/blog/tag/webdienst/feed/" rel="self" type="application/rss+xml" />
	<link></link>
	<description>alias RobbelRoot – Freelance Full Stack Developer .NET</description>
	<lastBuildDate>Sun, 19 Dec 2021 21:43:54 +0000</lastBuildDate>
	<language>de</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://robbelroot.de/wp-content/uploads/2020/12/cropped-favicon-32x32.png</url>
	<title>webdienst Archive - Robert Skibbe</title>
	<link></link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Wie man einen NodeJS Http Server erstellt</title>
		<link>https://robbelroot.de/blog/wie-man-einen-nodejs-http-server-erstellt/</link>
					<comments>https://robbelroot.de/blog/wie-man-einen-nodejs-http-server-erstellt/#comments</comments>
		
		<dc:creator><![CDATA[Robert Skibbe]]></dc:creator>
		<pubDate>Thu, 16 Dec 2021 19:28:54 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[NodeJS]]></category>
		<category><![CDATA[NodeJS Problemlösungen]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[anfragen]]></category>
		<category><![CDATA[antwort]]></category>
		<category><![CDATA[antworten]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[async]]></category>
		<category><![CDATA[asynchron]]></category>
		<category><![CDATA[beantworten]]></category>
		<category><![CDATA[dienst]]></category>
		<category><![CDATA[erstellen]]></category>
		<category><![CDATA[http]]></category>
		<category><![CDATA[https]]></category>
		<category><![CDATA[hypertext transfer protocol]]></category>
		<category><![CDATA[io]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[js]]></category>
		<category><![CDATA[microservice]]></category>
		<category><![CDATA[node]]></category>
		<category><![CDATA[nodejs]]></category>
		<category><![CDATA[request]]></category>
		<category><![CDATA[respond]]></category>
		<category><![CDATA[response]]></category>
		<category><![CDATA[schnittstelle]]></category>
		<category><![CDATA[secure]]></category>
		<category><![CDATA[server]]></category>
		<category><![CDATA[service]]></category>
		<category><![CDATA[sicher]]></category>
		<category><![CDATA[ssl]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[webdienst]]></category>
		<category><![CDATA[webschnittstelle]]></category>
		<category><![CDATA[webserver]]></category>
		<guid isPermaLink="false">https://robbelroot.de/?p=6901</guid>

					<description><![CDATA[<p>Wie Du einen NodeJS Http Server erstellen kannst, erfährst Du im heutigen Beitrag. Ich verzichte der Einfachheit halber und aufgrund der meiner Meinung nach sinnvollen Trennung auf weitere Frameworks. Für den Bau eines NodeJS Http Servers werden wir also nur die bereits vorhandenen Bordmittel von Node verwenden. Grundprinzipien eines (NodeJS) &#8230;</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/wie-man-einen-nodejs-http-server-erstellt/">Wie man einen NodeJS Http Server erstellt</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2021/12/NodeJS-Http-Server-erstellen.png"><img fetchpriority="high" decoding="async" width="1200" height="628" src="https://robbelroot.de/wp-content/uploads/2021/12/NodeJS-Http-Server-erstellen.png" alt="NodeJS Http Server erstellen" class="wp-image-6903" title="NodeJS Http Server erstellen"/></a><figcaption>NodeJS Http Server erstellen</figcaption></figure>






<p>Wie Du einen <strong>NodeJS Http Server</strong> erstellen kannst, erfährst Du im <strong>heutigen Beitrag</strong>.</p>



<p>Ich <strong>verzichte </strong>der Einfachheit halber und aufgrund der meiner Meinung nach sinnvollen Trennung <strong>auf</strong> <strong>weitere Frameworks</strong>.</p>



<p><strong>Für den Bau </strong>eines NodeJS Http Servers <strong>werden </strong>wir also <strong>nur </strong>die bereits <strong>vorhandenen Bordmittel </strong>von Node <strong>verwenden</strong>.</p>



<h2 class="wp-block-heading">Grundprinzipien eines (NodeJS) Http Servers</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2021/12/NodeJS-Http-Server-Basics.png"><img decoding="async" width="1200" height="628" src="https://robbelroot.de/wp-content/uploads/2021/12/NodeJS-Http-Server-Basics.png" alt="NodeJS Http Server Basics" class="wp-image-6920" title="NodeJS Http Server Basics"/></a><figcaption>NodeJS Http Server Basics</figcaption></figure>



<p><strong>Bevor </strong>wir <strong>in </strong>den <strong>Code </strong>und Weiteres <strong>starten </strong>würde ich sagen, dass wir uns <strong>erstmal </strong>den <strong>Basics </strong>des Webs widmen.</p>



<p><strong>Vielleicht </strong>ist Dir das <strong>Grundprinzip </strong>von Webservern bereits <strong>bekannt</strong>, <strong>dann </strong>bist Du natürlich herzlich <strong>eingeladen </strong>diesen Abschnitt zu <strong>überspringen</strong>.</p>



<p><strong>Für </strong>alle <strong>Anderen </strong>und die somit eventuellen Neulinge unter den Besuchern, <strong>schauen </strong>wir uns aber <strong>den Ablauf </strong>eines Webservers <strong>nochmal an</strong>.</p>



<p>Das <strong>Grundprinzip </strong>lässt sich auf <strong>viele Bereich </strong>übertragen, also <strong>nicht nur auf</strong> das simple &#8222;Serven&#8220; (Bereitstellen) <strong>einer Datei </strong>auf Anfrage.</p>



<p>Wenn Du Dir das <strong>Bild</strong> anschaust, siehst Du eine (oder mehrere) <strong>typische Situatione</strong>(n).</p>



<h3 class="wp-block-heading">Ablauf einer Anfrage</h3>



<p><strong>Links </strong>befinden sich die <strong>verwendeten Geräte</strong>, wie z. B. Laptops &amp; Desktop PCs, Smartphones und Tablets.</p>



<p>Diese <strong>rufen </strong>z. B. <strong>in </strong>Ihrem <strong>Browser </strong>eine bestimmte <strong>Website/Adresse </strong>auf, Sie senden also eine <strong>Anfrage an den Server</strong>.</p>



<p><strong>Danach schaut </strong>der <strong>Server </strong>nach seiner <strong>entsprechenden Logik</strong>, <strong>um </strong>die jeweilige Anfrage <strong>zu beantworten</strong>.</p>



<p><strong>Dabei sendet </strong>&#8222;er&#8220; <strong>verschiedene </strong>Daten <strong>in </strong>seiner <strong>Antwort </strong>wie z. B. den <strong>Kopf</strong>, oder den <strong>Body</strong>.</p>



<p>Der <strong>Inhalt </strong>der <strong>Antwort </strong>hängt natürlich <strong>unter Anderem </strong>stark von der <strong>Gestaltung </strong>des jeweiligen &#8222;Endpunktes&#8220; und der allgemeinen Server-Infrastruktur ab.</p>



<p><strong>Handelt </strong>es sich dabei um eine <strong>Datei </strong>sieht die <strong>Antwort anders </strong>aus, <strong>als </strong>wenn man nur über <strong>eine Schnittstelle </strong>diverse <strong>Kunden </strong>abrufen möchte.</p>



<h2 class="wp-block-heading">Das simpelste Beispiel</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2021/12/NodeJS-Http-Server-Simples-Beispiel.jpg"><img decoding="async" width="1280" height="853" src="https://robbelroot.de/wp-content/uploads/2021/12/NodeJS-Http-Server-Simples-Beispiel.jpg" alt="NodeJS Http Server - Simples Beispiel" class="wp-image-6938" title="NodeJS Http Server - Simples Beispiel"/></a><figcaption>NodeJS Http Server &#8211; Simples Beispiel</figcaption></figure>



<p>Ich <strong>denke </strong>es ist <strong>an der Zeit</strong>, für ein wirklich (wirklich) <strong>simples Beispiel </strong>eines <strong>Node Http Servers</strong>.</p>



<p>Schauen wir uns <strong>erstmal </strong>an, <strong>was </strong>wir aus der Standard-Bibliothek von Node (Module) <strong>verwenden </strong>können.</p>



<p>Wer sucht wird <strong>relativ schnell </strong>fündig und stößt auf das gute alte <strong>&#8222;Http&#8220;-Modul</strong> – wer hätte es gedacht.</p>



<h3 class="wp-block-heading">Das Http-Modul</h3>



<p><strong>Um </strong>das &#8222;Http&#8220;-<strong>Modul </strong>zu &#8222;<strong>importieren</strong>&#8220; und verwenden zu können, legen wir <strong>wie üblich </strong>eine <strong>Konstante </strong>mit jeweiligem Namen <strong>an</strong>.</p>



<p><strong>Des Weiteren </strong>brauchen wir <strong>noch </strong>die für Node Programme <strong>typische </strong>&#8222;<strong>require</strong>&#8222;-Funktion, welche das Modul letztendlich <strong>importiert und </strong>als <strong>Rückgabewert </strong>zurückgibt.</p>



<p>Solche <strong>Module können </strong>wir natürlich auch <strong>selbst schreiben</strong>, allerdings ist das ein <strong>Thema für </strong>einen <strong>späteren </strong>Beitrag!</p>



<p><strong>Legen </strong>wir also <strong>nun </strong>die <strong>Konstante an </strong>und verwenden Diese anschließend:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">const http = require('http')</pre>



<p><strong>Natürlich </strong>verwende ich <strong>hier </strong>eine <strong>Konstante</strong>, <strong>statt </strong>einer <strong>normalen Variable (var)</strong> oder &#8222;scoped&#8220; Variable <strong>(let)</strong>, da sich der dort drin stehende <strong>Wert nicht verändern </strong>wird/soll!</p>



<h3 class="wp-block-heading">Der Request-Handler</h3>



<p><strong>Danach </strong>erstellen wir einen <strong>Request-Handler</strong>, Welcher <strong>jeweils </strong>einen Request (eine Anfrage an den Server) <strong>verarbeiten </strong>wird.</p>



<p><strong>Dieser Handler </strong>ist letztendlich <strong>nichts anderes als </strong>eine kleine <strong>Funktion</strong>, Welche <strong>2 Parameter</strong> mitgeliefert bekommt – der Request und die Response.</p>



<p><strong>Damit </strong>bekommen wir die <strong>Möglichkeit Daten vom Request</strong> zu <strong>lesen</strong>, bzw. Daten <strong>in </strong>die <strong>Response zu schreiben</strong>.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">const requestHandler = function (req, res) {
  res.writeHead(200, { 'Content-Type': 'application/json' })
  res.write("NodeJS Http Server")
  res.end()
}</pre>



<h3 class="wp-block-heading">Server erstellen und ausführen</h3>



<p><strong>Im letzten Schritt </strong>des einfachen Beispiels müssen wir <strong>nur noch </strong>einen &#8222;<strong>Server</strong>&#8220; mit Hilfe der &#8222;<strong>createServer</strong>&#8222;-Funktion des <strong>&#8222;Http&#8220;-Moduls</strong> erstellen.</p>



<p><strong>Danach </strong>können wir dem <strong>Server </strong>einfach nur noch <strong>sagen</strong>: &#8222;Hör&#8216; zu!&#8220; und schon <strong>läuft </strong>das Ding!</p>



<p>Wir legen <strong>zuerst zwei Konstanten</strong> fest, Welche eine kleine <strong>Art Konfiguration</strong> widerspiegeln.</p>



<p><strong>Dabei </strong>sagen wir dem Programm, auf <strong>welchen Port </strong>bzw. auf welchen <strong>Host</strong>&#8211;<strong>Namen </strong>es lauschen soll:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">const port = 8000
const host = 'localhost'</pre>



<p><strong>Nun erstellen </strong>wir den <strong>Server indem </strong>wir einfach wie angekündigt die &#8222;createServer&#8220;-<strong>Funktion </strong>des &#8222;Http&#8220;-Moduls <strong>aufrufen</strong>.</p>



<p><strong>Dann rufen </strong>wir nur noch die &#8222;<strong>listen</strong>&#8222;-<strong>Funktion auf </strong>und <strong>schön </strong>&#8222;hört&#8220; unser <strong>Server </strong>auf ankommende <strong>Anfragen</strong>.</p>



<p><strong>Um </strong>eine <strong>Art Status auszugeben</strong>, geben wir der &#8222;listen&#8220;-Funktion <strong>noch </strong>ein anonymes <strong>Callback </strong>mit, Welches <strong>bei Start </strong>des Servers <strong>aufgerufen </strong>wird.</p>



<p><strong>Hier könnten </strong>wir natürlich <strong>auch </strong>ähnlich <strong>wie </strong>mit dem &#8222;Request-Handler&#8220; verfahren <strong>und </strong>eine <strong>benannte Funktion</strong>, statt einer Anonymen verwenden..</p>



<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">const server = http.createServer(requestHandler)
server.listen(port, host, function () {
  console.log(`Listening for requests on https://${host}:${port}`)
})</pre>



<p><strong>Nun </strong>kannst Du die <strong>Anwendung </strong>z. B. <strong>in Visual Studio Code</strong> <strong>über </strong>die <strong>Konsole ausführen </strong>(oder Du verwendest die normale Windows/Mac Konsole/Terminal).</p>



<p><strong>Öffne </strong>in Visual Studio Code ein <strong>Terminal mit </strong>dem <strong>Hotkey </strong>&#8222;Strg+Shift+ö&#8220;, <strong>oder </strong>gehe oben <strong>über&#8217;s Menü</strong>.</p>



<p><strong>Dann </strong>musst Du den <strong>obigen Code</strong> nur noch <strong>in </strong>eine <strong>JavaScript-Datei</strong>, z. B. &#8222;index.js&#8220; stecken <strong>und </strong>mit &#8222;node index.js&#8220; (geht auch ohne &#8222;.js&#8220;) <strong>ausführen</strong>.</p>



<figure class="wp-block-image size-full is-resized"><a href="https://robbelroot.de/wp-content/uploads/2021/12/NodeJS-Http-Server-Ausgabe.png"><img loading="lazy" decoding="async" src="https://robbelroot.de/wp-content/uploads/2021/12/NodeJS-Http-Server-Ausgabe.png" alt="NodeJS Http Server - Ausgabe" class="wp-image-6953" width="418" height="192" title="NodeJS Http Server - Ausgabe"/></a><figcaption>NodeJS Http Server &#8211; Ausgabe</figcaption></figure>



<p>Wenn Du <strong>dann </strong>die <strong>konfigurierte Adresse </strong>&#8222;<strong><a href="https://localhost:8000" target="_blank" rel="noreferrer noopener">https://localhost:8000</a></strong>&#8220; <strong>besuchst</strong>, dürfest Du <strong>folgende Ausgabe </strong>sehen:</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2021/12/NodeJS-Http-Server-Web-Ausgabe.png"><img loading="lazy" decoding="async" width="261" height="83" src="https://robbelroot.de/wp-content/uploads/2021/12/NodeJS-Http-Server-Web-Ausgabe.png" alt="NodeJS Http Server - Web Ausgabe" class="wp-image-6960" title="NodeJS Http Server - Web Ausgabe"/></a></figure>



<h3 class="wp-block-heading">Fazit</h3>



<p><strong>Nun </strong>haben wir das simple <strong>Beispiel abgeschlossen</strong>, jedoch <strong>kommen </strong>in <strong>Zukunft </strong>noch weitere <strong>Problematiken </strong>auf uns zu.</p>



<p><strong>Diese kommen </strong>unter Anderem <strong>dann</strong>, <strong>wenn </strong>man mit <strong>einzelnen </strong>Routen/<strong>Endpunkten und auch </strong>z. B. einer <strong>Authentifizierung </strong>arbeiten möchte.</p>



<p>Mit dem <strong>aktuellen Stand </strong>könnten wir also <strong>keine wirklich </strong>sinnvolle, bzw. eher <strong>vielfältige Applikation </strong>bauen – zumindest nicht so easy..</p>



<p>Das <strong>aktuelle Skript </strong>arbeitet praktisch als &#8222;<strong>Catch-All-Route</strong>&#8222;, es <strong>arbeitet </strong>also <strong>jeden GET-Request</strong> bisher gleich ab.</p>



<p><strong>Egal ob </strong>wir &#8222;&lt;adresse&gt;/kunden&#8220;, <strong>oder </strong>&#8222;&lt;adresse&gt;/dashboard&#8220; aufrufen, es kommt <strong>immer </strong>das <strong>Gleiche </strong>als <strong>Antwort</strong>.</p>



<p>Das <strong>liegt </strong>natürlich <strong>daran</strong>, <strong>dass </strong>wir in dem obigen Skript <strong>in keiner Weise zwischen </strong>verschiedenen <strong>Endpunkten zu unterscheiden</strong>.</p>



<h3 class="wp-block-heading">Simpler NodeJS Http Server Code</h3>



<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">const http = require('http')
const requestHandler = function (req, res) {
  res.writeHead(200, { 'Content-Type': 'application/json' })
  res.write('NodeJS Http Server')
  res.end()
}
const port = 8000
const host = 'localhost'
const server = http.createServer(requestHandler)
server.listen(port, host, function () {
  console.log(`Listening for requests on https://${host}:${port}`)
})</pre>



<h2 class="wp-block-heading">Erweitertes NodeJS Http Server Beispiel im Selbstversuch</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2021/12/NodeJS-Http-Server-Erweitertes-Beispiel.png"><img loading="lazy" decoding="async" width="698" height="465" src="https://robbelroot.de/wp-content/uploads/2021/12/NodeJS-Http-Server-Erweitertes-Beispiel.png" alt="NodeJS Http Server - Erweitertes Beispiel" class="wp-image-6983" title="NodeJS Http Server - Erweitertes Beispiel"/></a><figcaption>NodeJS Http Server &#8211; Erweitertes Beispiel</figcaption></figure>



<p><strong>Nachdem </strong>wir nun oben schon <strong>einige Fallstricke </strong>feststellen konnten, schauen wir uns <strong>im nächsten Abschnitt </strong>mal einen kleinen <strong>Selbstversuch </strong>an.</p>



<p>Wir <strong>schreiben </strong>uns eine eigene <strong>kleine Server</strong>&#8211;<strong>Klasse</strong>, mit dessen Hilfe wir <strong>verschiedene Request-Arten und Routen</strong> registrieren können.</p>



<p><strong>Wie </strong>Dir <strong>vielleicht bekannt </strong>ist, gibt es <strong>nicht nur </strong>die <strong>oben verwendete </strong>Http &#8222;GET&#8220;-<strong>Methode</strong>, <strong>sondern </strong>z. B. <strong>noch </strong>&#8222;POST&#8220;, &#8222;PUT&#8220;, &#8222;DELETE&#8220; und mehr.</p>



<p><strong>Ein Beispiel wäre ein </strong>&#8222;<strong>GET</strong>&#8222;-<strong>Request </strong>an den &#8222;/kunden&#8220;-Endpunkt, Welcher z. B. eine Suche signalisiert und eventuell noch Query-Parameter zur Filterung a la &#8222;?name=Max&#8220; entgegennehmen kann.</p>



<p><strong>Wenn man </strong>nun allerdings ein <strong>&#8222;POST&#8220;-Request</strong> an den &#8222;/kunden&#8220;-Endpunkt <strong>schickt</strong>, <strong>könnte man </strong>durch die Angabe passender Daten z. B. <strong>einen Kunden erstellen</strong>.</p>



<h3 class="wp-block-heading">Los geht&#8217;s – die jetzt benötigten Module</h3>



<p><strong>Bei </strong>dem <strong>erweiterten Beispiel</strong>-Server benötigen wir im Vergleich zu vorhin einige <strong>zusätzliche Module</strong>.</p>



<p>Wir <strong>möchten </strong>natürlich <strong>so viel </strong>Arbeit <strong>wie </strong>nur <strong>möglich an </strong>die <strong>Core</strong>-Module von NodeJS <strong>abgeben</strong>.</p>



<p><strong>Darunter fällt </strong>zum Beispiel das <strong>Verarbeiten</strong>, also das <strong>Parsen des Url</strong>-Strings, bestehend aus <strong>Endpunkt </strong>und <strong>Query</strong>&#8211;<strong>Parameter</strong>.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">const http = require('http'),
  url = require('url'),
  querystring = require('querystring')</pre>



<h3 class="wp-block-heading">Die Server-Klasse</h3>



<p><strong>Im Optimalfall </strong>stellt man sich die <strong>Konfiguration </strong>des Servers meiner Meinung nach <strong>so</strong> aktuell am besten vor:</p>



<pre class="wp-block-code"><code>- Server instanziieren
- Routen definieren
- Server lauschen lassen und Handler die Arbeit machen lassen</code></pre>



<p><strong>Daher </strong>werde ich den <strong>Server </strong>nach Möglichkeit genau <strong>so </strong>versuchen in kurzer Zeit zu <strong>bauen </strong>– damit es <strong>nicht den Rahmen sprengt</strong>.</p>



<p><strong>Selbstverständlich </strong>ist Deine eigene <strong>Kreativität gerne gesehen </strong>und <strong>keine Grenzen </strong>in Sicht, &#8222;do your thing&#8220; sag ich mal!</p>



<p><strong>Definieren </strong>wir also im <strong>ersten Schritt </strong>eine simple JavaScript-Klasse <strong>mit </strong>unserem <strong>gewünschten </strong>&#8222;Skelett&#8220;-Aufbau:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class Server {
  constructor () {
    // doin' some constructional things
  }
  get () {
    // registering a GET route..
  }
  post () {
    // registering a POST route..
  }
  start () {
    // starting the server making it listening to requests
  }
}</pre>



<h4 class="wp-block-heading">Der Konstruktor</h4>



<p>Im <strong>Konstruktor </strong>des Servers <strong>übergeben </strong>wir die Haupt-<strong>Konfiguration</strong>, wie den <strong>Hostname und</strong> den <strong>Port</strong>.</p>



<p>Ggf. <strong>könnte </strong>man es <strong>auch </strong>hier <strong>mit </strong>einem <strong>&#8222;options&#8220;-Objekt</strong> gestalten, <strong>allerdings </strong>ist das für&#8217;s Erste nicht notwendig.</p>



<p><strong>Meistens bietet </strong>es sich aber tatsächlich <strong>an</strong>, <strong>da </strong>die <strong>Konfigurationsmöglichkeiten </strong>häufig von Zeit zu Zeit <strong>wachsen und</strong> man natürlich sowas wie <strong>7 Konstruktor-Parameter vermeiden</strong> sollte.</p>



<p><strong>Zuerst </strong>kümmern wir uns um <strong>Auflistung</strong>, Welche <strong>später </strong>die <strong>einzelnen </strong>registrierten <strong>Routen </strong>enthalten wird.</p>



<h5 class="wp-block-heading">Ein Workaround</h5>



<p>Ich <strong>habe </strong>hier <strong>bewusst </strong>eine <strong>anonyme Funktion mit &#8222;Arrow-Function&#8220;-Deklaration</strong> gewählt, um den &#8222;This-<strong>Scope</strong>&#8220; des <strong>Konstruktors </strong>zu behalten.</p>



<p>So <strong>komme </strong>ich <strong>kinderleicht an </strong>das &#8222;_routes&#8220; <strong>Feld</strong>/Eigenschaft – bau&#8216; dies gern nach Belieben um..</p>



<p><strong>Würde </strong>ich hingegen eine <strong>weitere Methode in </strong>der <strong>Klasse </strong>hinzufügen, würde ich <strong>innerhalb der Methode</strong> den <strong>Scope </strong>des &#8222;http&#8220;-Moduls haben (und somit nicht an die Routes kommen..).</p>



<p><strong>Nachdem </strong>die &#8222;<strong>createServer</strong>&#8222;-Funktion ihr Ding macht, <strong>nehmen </strong>wir noch <strong>Standardwerte für </strong>die <strong>Konfiguration </strong>(host, port) auf und setzen Sie <strong>ansonsten </strong>wie <strong>übergeben</strong>.</p>



<h5 class="wp-block-heading">Vorgehensweise</h5>



<p>Das <strong>Callback </strong>der &#8222;createServer&#8220;-Funktion <strong>loggt </strong>im ersten Schritt die <strong>besuchte Url inkl. Route</strong>, damit wir verfolgen können was passiert.</p>



<p><strong>Danach verarbeiten </strong>wir mit einer der oben angesprochenen Utility-Module die <strong>Request</strong>&#8211;<strong>Url</strong>.</p>



<p><strong>Somit </strong>können wir dann <strong>kinderleicht </strong>an den <strong>Pfad </strong>kommen (z. B. &#8222;/customers&#8220;) und <strong>müssen </strong>hier <strong>nicht nach </strong>dem <strong>Query-String schauen</strong>.</p>



<p><strong>Dieser </strong>kommt zu einem <strong>späteren Zeitpunkt </strong>noch bei z. B. der Filterung <strong>zum Einsatz</strong>.</p>



<p><strong>Ansonsten </strong>machen wir das, was viele Server machen, wenn Sie eine <strong>Url nicht finden </strong>können.</p>



<p>Sie <strong>melden </strong>einen <strong>404-Fehler</strong> und wir verlassen dann den Durchlauf mit einem &#8222;<strong>Early Return</strong>&#8222;!</p>



<p><strong>Falls </strong>die <strong>Route </strong>jedoch <strong>gefunden </strong>wird, sich also eine <strong>zum Pfad und zur Request-Methode passende Route</strong> in unserer Auflistung befindet, ziehen wir Diese.</p>



<p>Zum Schluss rufen wir dann den dafür registrierten Handler der Route auf und übergeben das <strong>Request- &amp; Response-Objekt</strong> als Parameter.</p>



<p>So <strong>können </strong>die <strong>Handler entscheiden</strong>, <strong>was </strong>Sie mit den dem jeweiligen Objekt <strong>machen </strong>und der <strong>zentralen Stelle </strong>oben <strong>obliegt </strong>einzig und allein die <strong>Delegation </strong>– schön!</p>



<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// ..
constructor(host, port) {
    const routes = []
    this._routes = routes
    this._server = http.createServer((req, res) => {
      console.log(`[${req.method}] ${req.url}`)
      const requestUrl = url.parse(req.url)
      const route = routes.find(x => x.path === requestUrl.pathname &amp;&amp; x.method === req.method)
      if (!route) {
        res.writeHead(404, { 'Content-Type': 'application/json' })
        res.write('Route not found')
        res.end()
        return
      }
      route.handler(req, res)
    })
    this._host = host || 'localhost'
    this._port = port || 8000
  }
// ..</pre>



<h3 class="wp-block-heading">Ein paar Hilfsmethoden</h3>



<p><strong>Normalerweise </strong>bin ich <strong>kein Fan von </strong>komplexen <strong>Abfang-Szenarien</strong> in Beispiel-Codes, <strong>allerdings </strong>dürfte das hier relativ <strong>überschaubar </strong>sein, daher..</p>



<p>Wir <strong>definieren 3 Methoden</strong>, Welche die <strong>Überprüfung </strong>der notwendigen <strong>Argumente/Parameter</strong> bei einer Routen-Registrierung übernehmen.</p>



<p>Man hat ja <strong>schließlich keine Lust </strong>(und es ist schlechter Coding-Stil), alles <strong>5 mal zu schreiben</strong> – <strong>duplicated Code</strong>, bah!</p>



<h4 class="wp-block-heading"> <strong>_checkPath</strong>-Methode</h4>



<p><strong>Nun </strong>gibt es also die &#8222;<strong>_checkPath</strong>&#8222;-Methode, <strong>Welche </strong>einfach nur <strong>prüft</strong>, <strong>ob </strong>das übergebene <strong>Argument &#8222;ok&#8220;</strong> ist, also nicht &#8222;leer&#8220; und vom Typ String.</p>



<p><strong>Zusätzlich prüft </strong>die Methode noch, <strong>ob </strong>schonmal eine <strong>gleiche Route </strong>registriert wurde (unabhängig vom Handler..).</p>



<h4 class="wp-block-heading">_checkHandler-Methode</h4>



<p>Die &#8222;_checkHandler&#8220;-Methode <strong>prüft </strong>auch <strong>ob überhaupt </strong>etwas <strong>übergeben </strong>wurde <strong>und </strong>zusätzlich, <strong>ob </strong>es sich dabei auch um eine gewünschte <strong>Funktion </strong>handelt.</p>



<h4 class="wp-block-heading">_registerRoute-Methode</h4>



<p><strong>Als nächstes </strong>kommt das <strong>Routen-Helferlein</strong> zum Einsatz, Welches uns – wer hätte es gedacht.. – <strong>bei </strong>der <strong>Registrierung </strong>einer <strong>Route </strong>unterstützt.</p>



<p><strong>Auch hier </strong>gilt wieder die <strong>Vermeidung von duplicated Code</strong>, etc..</p>



<p>Es wird ein <strong>neues Route-Objekt</strong> mit Hilfe der angegebenen Parameter erstellt <strong>und </strong>der <strong>Auflistung hinzugefügt</strong>.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">  _checkPath(path, method) {
    if (!path || typeof path !== 'string') {
      throw new Error('No or invalid path specified')
    }
    const existentRoute = this._routes.find(x => x.path === path &amp;&amp; x.method === method)
    if (existentRoute) {
      throw new Error(`Route already registered [${method}] ${path}`)
    }
  }
  _checkHandler(handler) {
    if (!handler || typeof handler !== 'function') {
      throw new Error('No or invalid handler specified')
    }
  }
  _registerRoute(path, method, handler) {
    const route = {
      path,
      method,
      handler,
    }
    this._routes.push(route)
  }</pre>



<h3 class="wp-block-heading">Routen registrieren</h3>



<p>Im <strong>Folgenden Code </strong>werden <strong>zwei Möglichkeiten </strong>einer Routen-<strong>Registrierung </strong>definiert:</p>



<ul class="wp-block-list"><li>GET-Routen</li><li>POST-Routen</li></ul>



<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">  get(path, handler) {
    this._checkPath(path, 'GET')
    this._checkHandler(handler)
    this._registerRoute(path, 'GET', handler)
  }
  post(path, handler) {
    this._checkPath(path, 'POST')
    this._checkHandler(handler)
    this._registerRoute(path, 'POST', handler)
  }</pre>



<p><strong>Dabei </strong>wird bis auf die <strong>Request-Methode</strong> <strong>nicht </strong>wirklich etwas <strong>anderes </strong>gemacht, könnte man ggf. auch anders gestalten, aber cmon..</p>



<h3 class="wp-block-heading">Den Server starten</h3>



<p><strong>Um </strong>den Server zu <strong>starten</strong>, müssen wir auf das <strong>klasseninterne Feld</strong> namens &#8222;_server&#8220; zugreifen und dessen &#8222;<strong>listen</strong>&#8222;-Methode <strong>aufrufen</strong>.</p>



<p><strong>Ggf</strong>. <strong>könnte </strong>man hier noch mit irgendwelchen <strong>Zustands-Flags</strong> für einen noch zu <strong>implementierenden Stop </strong>realisieren.</p>



<p>Kommen wir <strong>nun </strong>zu einer <strong>Beispiel-Konfiguration</strong> <strong>und </strong>einer Art Kunden-<strong>API</strong>.</p>



<p><strong>Dazu erstelle </strong>ich eine (nicht persistente, nur im Server-Memory existierende) <strong>Kunden-Auflistung</strong>.</p>



<p><strong>Als nächstes </strong>instanziiere ich wie oben geplant eine neue <strong>Server</strong>&#8211;<strong>Instanz</strong>.</p>



<p>Im <strong>Anschluss </strong>werden die <strong>Routen registriert und </strong>der Server durch die &#8222;start&#8220;-Methode <strong>gestartet</strong>.</p>



<h4 class="wp-block-heading">Die Such-Route für die Kunden</h4>



<p>Die <strong>erste </strong>zu registrierende <strong>Route </strong>wäre die <strong>Such-Route für die Kunden</strong> (bzw. die Schnittstelle..).</p>



<p><strong>Pro Anfrage </strong>entsteht im ersten Schritt ein <strong>neues Array mit </strong>dem <strong>Inhalt </strong>der <strong>ursprünglichen </strong>&#8222;customers&#8220;-Auflistung.</p>



<p>Dann <strong>führen </strong>wir ein paar <strong>Prüfungen </strong>durch, <strong>ob </strong>es <strong>wirklich</strong> eine <strong>Suche </strong>ist, also <strong>ob </strong>wirklich <strong>Suchparameter übergeben </strong>wurden.</p>



<p><strong>Falls ja filtern </strong>wie die &#8222;responseCustomers&#8220; und weisen der gleichen Variable das neue Ergebnis zu.</p>



<p><strong>So </strong>könnte man Schritt für Schritt natürlich <strong>weitere Such-Möglichkeiten hinzufügen</strong>.</p>



<p><strong>Zum Schluss </strong>geben wir die <strong>Daten </strong>JSON-konform <strong>an </strong>den aufrufenden <strong>Client aus </strong>– fertig!</p>



<p><strong>Gerne </strong>darfst Du Dich daran versuchen, die <strong>fehlende POST-Route zu bauen</strong> *zwinker*.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">const customers = [
  {
    company: 'Nice Company ltd.'
  },
  {
    company: 'Another Company'
  },
]
const server = new Server()
server.get('/customers', (req, res) => {
  let responseCustomers = [...customers]
  const shouldFilter = req.url.includes('?') &amp;&amp; req.url.includes('=')
  if (shouldFilter) {
    const requestUrl = url.parse(req.url)
    const query = querystring.parse(requestUrl.query)
    const hasNameFilter = 'name' in query
    if (hasNameFilter) {
      const nameToFilter = (query['name'] || '').toLowerCase()
      if (nameToFilter) {
        responseCustomers = responseCustomers.filter(x => x.company.toLowerCase().includes(nameToFilter))
      }
    }
  }
  res.writeHead(200, { 'Content-Type': 'application/json' })
  res.write(JSON.stringify(responseCustomers))
  res.end()
})
server.post('/customers', (req, res) => {
  // to be done..
})
server.start()</pre>



<h3 class="wp-block-heading">Erweiterter NodeJS Http Server Code </h3>



<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">const http = require('http'),
  url = require('url'),
  querystring = require('querystring')

class Server {
  constructor(host, port) {
    this._routes = []
    this._server = http.createServer((req, res) => {
      console.log(`[${req.method}] ${req.url}`)
      const requestUrl = url.parse(req.url)
      const route = this._routes.find(x => x.path === requestUrl.pathname &amp;&amp; x.method === req.method)
      if (!route) {
        res.writeHead(404, { 'Content-Type': 'application/json' })
        res.write('Route not found')
        res.end()
        return
      }
      route.handler(req, res)
    })
    this._host = host || 'localhost'
    this._port = port || 8000
  }
  _checkPath(path, method) {
    if (!path || typeof path !== 'string') {
      throw new Error('No or invalid path specified')
    }
    const existentRoute = this._routes.find(x => x.path === path &amp;&amp; x.method === method)
    if (existentRoute) {
      throw new Error(`Route already registered [${method}] ${path}`)
    }
  }
  _checkHandler(handler) {
    if (!handler || typeof handler !== 'function') {
      throw new Error('No or invalid handler specified')
    }
  }
  _registerRoute(path, method, handler) {
    const route = {
      path,
      method,
      handler,
    }
    this._routes.push(route)
  }
  get(path, handler) {
    this._checkPath(path, 'GET')
    this._checkHandler(handler)
    this._registerRoute(path, 'GET', handler)
  }
  post(path, handler) {
    this._checkPath(path, 'POST')
    this._checkHandler(handler)
    this._registerRoute(path, 'POST', handler)
  }
  start() {
    this._server.listen(this._port, this._host, () => {
      console.log(`Listening for requests on https://${this._host}:${this._port}`)
    })
  }
}

const customers = [
  {
    company: 'Nice Company ltd.'
  },
  {
    company: 'Another Company'
  },
]
const server = new Server()
server.get('/customers', (req, res) => {
  let responseCustomers = [...customers]
  const shouldFilter = req.url.includes('?') &amp;&amp; req.url.includes('=')
  if (shouldFilter) {
    const requestUrl = url.parse(req.url)
    const query = querystring.parse(requestUrl.query)
    const hasNameFilter = 'name' in query
    if (hasNameFilter) {
      const nameToFilter = (query['name'] || '').toLowerCase()
      if (nameToFilter) {
        responseCustomers = responseCustomers.filter(x => x.company.toLowerCase().includes(nameToFilter))
      }
    }
  }
  res.writeHead(200, { 'Content-Type': 'application/json' })
  res.write(JSON.stringify(responseCustomers))
  res.end()
})
server.post('/customers', (req, res) => {

})
server.start()
</pre>



<h2 class="wp-block-heading">Du willst mehr!?</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2021/12/NodeJS-Http-Server-Express-JS.jpg"><img loading="lazy" decoding="async" width="1280" height="853" src="https://robbelroot.de/wp-content/uploads/2021/12/NodeJS-Http-Server-Express-JS.jpg" alt="NodeJS Http Server - Komplexere Anwendungen mit Express JS" class="wp-image-6972" title="NodeJS Http Server - Komplexere Anwendungen mit Express JS"/></a><figcaption>NodeJS Http Server &#8211; Komplexere Anwendungen mit Express JS (Bild nicht offiziell)</figcaption></figure>



<p><strong>Wenn Du mehr willst</strong>, sprich Deine Anwendung wirklich <strong>komplex gestalten </strong>möchtest, kommst Du nicht um das <strong>non plus ultra Framework</strong> herum.</p>



<p><strong>Dabei </strong>handelt es sich <strong>um </strong>das in Node-Kreisen sehr <strong>bekannte ExpressJS Framework</strong>.</p>



<p><strong>Neben </strong>gewisse <strong>Basis-Funktionen</strong> <strong>wie </strong>die einfache <strong>Definition von Routen </strong>unterstützt ExpressJS <strong>auch </strong>noch ein Konzept namens &#8222;<strong>Middlewares</strong>&#8222;.</p>



<p><strong>Hierüber </strong>werde ich allerdings noch <strong>in </strong>einem <strong>getrennten Beitrag </strong>schreiben, da es sonst zu viel wird!</p>



<h2 class="wp-block-heading">Downloads</h2>



<div class="wp-block-buttons is-layout-flex wp-block-buttons-is-layout-flex">
<div class="wp-block-button"><a class="wp-block-button__link" href="/downloads/nodejs/HttpServerExample.zip" target="_blank" rel="noreferrer noopener">HttpServerExample.zip</a></div>



<div class="wp-block-button"><a class="wp-block-button__link" href="/downloads/nodejs/AdvancedHttpServerExample.zip" target="_blank" rel="noreferrer noopener">AdvancedHttpServerExample.zip</a></div>
</div>



<h2 class="wp-block-heading">Weiterführende Links</h2>



<ul class="wp-block-list"><li><strong><a href="https://robbelroot.de/blog/nodejs-verzeichnisse-mit-readdirsync-synchron-einlesen/" target="_blank" rel="noreferrer noopener">NodeJS Verzeichnisse mit readdirSync auslesen</a></strong></li><li><strong><a href="https://robbelroot.de/blog/wie-man-einen-nodejs-qrcode-scanner-erstellt/" target="_blank" rel="noreferrer noopener">NodeJS QRCode Scanner erstellen</a></strong></li></ul>
<p>Der Beitrag <a href="https://robbelroot.de/blog/wie-man-einen-nodejs-http-server-erstellt/">Wie man einen NodeJS Http Server erstellt</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://robbelroot.de/blog/wie-man-einen-nodejs-http-server-erstellt/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
	</channel>
</rss>
