Pit: node.js-Express Kurzschreibweise/Platzhalter gesucht

Hallo,

im Modul Express von node.js notiere ich:

app.get("/index", function(req, res) {
res.sendFile('/public/index.html', { root: __dirname });
});

app.get("/kontakt", function(req, res) {
res.sendFile('/public/kontakt.html', { root: __dirname });
});

usw.

Kann ich das, wenn noch 20 Unterseiten geroutet werden sollen, mit Platzhaltern erledigen oder muß ich die alle 20 so notieren?

Pit

  1. Tach!

    Kann ich das, wenn noch 20 Unterseiten geroutet werden sollen, mit Platzhaltern erledigen oder muß ich die alle 20 so notieren?

    Was sagt denn die Dokumentation? Außerdem kann man auch ein Array erstellen und darüber iterierend die Einträe erstellen.

    dedlfix.

    1. Hi dedlfix,

      Was sagt denn die Dokumentation? Außerdem kann man auch ein Array erstellen und darüber iterierend die Einträe erstellen.

      Die Doku sagt dies...

      Daraus schloss ich das:

      app.get(':name', function(req, res) {
      var fileName = req.params.name;
      res.sendFile('/public/' + fileName + '.html', { root: __dirname });
      });
      
      

      Aber :name wird nicht erkannt/geroutet.

      Wenn ich localhost:3000/index aufrufe, erhalte ich

      Cannot GET /index

      Pit

      1. Tach!

        Was sagt denn die Dokumentation?

        Die Doku sagt dies...

        Daraus schloss ich das:

        app.get(':name', function(req, res) {
        

        Aber :name wird nicht erkannt/geroutet.

        Wenn ich localhost:3000/index aufrufe, erhalte ich

        Cannot GET /index

        In der Dokumentation starten die Pfade in allen Beispielen mit /. Vielleicht ist das das Problem, weil du keinen angegeben hast.

        dedlfix.

        1. Guten Morgen Dedlfix,

          In der Dokumentation starten die Pfade in allen Beispielen mit /. Vielleicht ist das das Problem, weil du keinen angegeben hast.

          Du hast recht, daran lag es. Dank' Dir für die Hilfe.

          
          // Funktioniert
          app.get('/:name', function(req, res) {
          var fileName = req.params.name;
          res.sendFile('/public/' + fileName + '.html', { root: __dirname });
          });
          

          funktioniert wie gewünscht. Ich habe den Code nur noch um eine Fehlerbehandlung ergänzt, so dass es mir gefällt.

          app.get('/:name', function(req, res, next) {
          var fileName = req.params.name;
            var options = {
              root: __dirname + '/public/'
            };
            res.sendFile(fileName + '.html', options, function (err) {
              if (err) {
                console.log('Sent:', err);
                res.status(404).send('Fehler 404: Datei nicht gefunden!');
              } else {
                console.log('Sent:', fileName);
              }
            });
          });
          

          Pit

          1. 
            // Funktioniert
            app.get('/:name', function(req, res) {
            var fileName = req.params.name;
            res.sendFile('/public/' + fileName + '.html', { root: __dirname });
            });
            

            Express hat auch schon eine Middleware für statische Dateiserver dabei, die könntest du ebenfalls benutzen:

            app.use(express.static('public', {extensions: '.html'))
            
  2. Hallo,

    Kann ich das, wenn noch 20 Unterseiten geroutet werden sollen, mit Platzhaltern erledigen oder muß ich die alle 20 so notieren?

    Nun, stell Dir doch einmal vor, Du würdest das für alle möglichen Seiten so machen, egal ob das jetzt 20 sind oder 1000.

    Dann würde Dein Programm bei jedem Request sämtlichen Code für alle diese Seiten compilieren und das, obwohl der Request nur auf eine von diesen Seiten erfolgt!

    Die Frage ob das sinnvoll ist, beantwortet sich von selbst. Und die Lösung hierzu heißt: Routing-Table.

    MfG

    1. Hallo Rolf,

      Die Frage ob das sinnvoll ist, beantwortet sich von selbst. Und die Lösung hierzu heißt: Routing-Table.

      Es geht um ein erstes Übungsprojekt für komplette Webtechnologie-Einsteiger, die zuvor noch nie etwas von HTML,CSS,JS, node.js und dergleichen mehr gehört haben.

      Routing-Tabelle: Hast Du mal ein Beispiel für mich?

      Pit

      1. hi

        Routing-Tabelle: Hast Du mal ein Beispiel für mich?

        Nehmen wir doch einfach ein JS-Objekt! Das können wir aus dem Code komplett rausnehmen in Form eines JSON. Der erste Schlüssel ist der URL:

        /* Statische Routen */
        static routes = {
            '/index.html' : {},
            '/about.html' : {},
            '/impressum.html' : {}
        };
        

        und in das an den URL gebundene Hash/Objekt{} liegen sämtliche Attribute welche zum Ausliefern der Response benötigt werden. Z.B. der Name der an den URL gebundenen Klasse oder der Name einer besimmten Methode, der Dateiname für das Template, Titel, Description usw.

        Wenn der Request jetzt reinkommt, erst dann setzt sich die Maschine in Bewegung und zwar nur da wo das steht, was zur angeforderten Seite gehört -- nur das wird ja gebraucht.

        Gegenüber vorher hast Du jetzt nur noch die Routingtable statisch im Hauptspeicher rumliegen, nicht jedoch den ganzen Code. Und Du hast die ganze Konfiguration vom Code getrennt.

        MfG

        1. Hi Rolf,

          Nehmen wir doch einfach ein JS-Objekt! Das können wir aus dem Code komplett rausnehmen in Form eines JSON. Der erste Schlüssel ist der URL:

          /* Statische Routen */
          static routes = {
              '/index.html' : {},
              '/about.html' : {},
              '/impressum.html' : {}
          };
          

          und in das an den URL gebundene Hash/Objekt{} liegen sämtliche Attribute welche zum Ausliefern der Response benötigt werden. Z.B. der Name der an den URL gebundenen Klasse oder der Name einer besimmten Methode, der Dateiname für das Template, Titel, Description usw.

          Mir ist noch gar nicht so klar, wie man JSON in eine ansonsten fertige HTML-Seite einbaut. Hast du da auch ein Beispiel oder einen Link für mich? Denn unabhängig von der Routingtabelle (die Idee finde ich gut) würde ich das auch für andere aspekte des Projekts benötigen und suche mir gerade 'nen Ast diesbzgl.

          Pit

          1. hi,

            Mir ist noch gar nicht so klar, wie man JSON in eine ansonsten fertige HTML-Seite einbaut.

            Gar nicht. JSON beschreibt nur die Art und Weise auf welche die Routingtable gespeichert werden kann. Für die serverseitige Anwendung jedoch, muss die Routingtable für den wahlfreien Zugriff im Hauptspeicher liegen, d.h., spätestens hier reden wir nicht mehr von JSON sondern von Objekten.

            Wahlfreier Zugriff: Request auf /index.html ist bspw. der Schlüssel zum Objekt{} in welchem sämtliche Attribute zu /index.html konfiguriert sind. Also der Name einer Methode, welche die Response auf /index.html zusammenzubauen hat.

            Du musst Dein Framework nur dazu bringen, daß es bei jedem Request in die Routingtable guckt welche Methode oder Klasse zum requesteten URL aufzurufen ist und die Response ausliefert. Das ist das ganze Geheimnis eines (jeden) Frameworks.

            Die Routingtable könnte auch so aussehen, daß zu jedem URL dieselbe Methode aufgerufen wird, nur mit einem anderen Template. Also alldas was die Responses vom Inhalt unterscheidet, wird über weitere Attribute geregelt, so gibt es zu jedem URL einen title und ein Template für den <body>. Letzeres liegt im einfachsten Fall als Datei im serverseitigen Verzeichnis was für Templates vorgesehen ist.

            MfG

            1. Hi Rolf,

              ehrlich gesagt bin ich nicht sicher, dass Deine Routingtabelle das richtige Mittel der Wahl für diesen Fall ist.

              Ich glaube, mit meiner Lösung besser zu fahren.

              Sie ist universeller, weil ich einfach neue HTML-Seiten anlegen kann, die dann auch geroutet werden, ohne in die Routiungtabelle aufgenommen zu werden. Prinzipiell glaube ich auch, dass Routing über Parameter sinvoller ist. Stell Dir einen Blog vor, der Tageseinträge enthält. Über meine Art Routing kann jeder Tag angesprochen werden:

              app.get('/blog/:year'/:month/:day?, function(req, res) {

              routet alle relevanten Requests nach demselben Schema, hier sogar wahlweise ohne oder mit Tag.

              Stell Dir das in einer Routingtabelle vor.

              Oder stell Dir vor, dass in mienem Beispiel HTML-Dateien bei der Nutzung der Webseite generiert werden, die aber auch geroutet werden sollen... was dann?

              Dennoch bleibt ein Problem, was ich weiter oben schon angesprochen hatte, erhalten:

              Wie lese ich in .json -Dateien hinterlegte Daten aus und integriere sie in die Webseite (die dann quasi als Template fungiert)?

              Von der Technik her ist mir das eigentlich klar:

              • Datei einlesen (hier würde ich fs.readJsonSync verwenden / Modul:fs-extra)
              • entsprechende Elemente generieren und in die HTML Datei integrieren
              • Inhalt in Elemente
              • HTML-Datei ausliefern

              Aber rein praktisch fehlts mir vielleicht an einem Beispiel. Jedenfalls bekomme ich das mit node.js und Javascript nicht hin. Mit php und JQuery wärs kein Problem, aber darum gehts ja nicht.

              Pit

              1. Dennoch bleibt ein Problem, was ich weiter oben schon angesprochen hatte, erhalten:

                Wie lese ich in .json -Dateien hinterlegte Daten aus und integriere sie in die Webseite (die dann quasi als Template fungiert)?

                Von der Technik her ist mir das eigentlich klar:

                • Datei einlesen (hier würde ich fs.readJsonSync verwenden / Modul:fs-extra)
                • entsprechende Elemente generieren und in die HTML Datei integrieren
                • Inhalt in Elemente
                • HTML-Datei ausliefern

                Aber rein praktisch fehlts mir vielleicht an einem Beispiel. Jedenfalls bekomme ich das mit node.js und Javascript nicht hin.

                Benutz lieber fsPromises um Dateien zu lesen, damit kannst du den Code synchron aussehen lassen und dennoch die Vorteile von non-blocking IO genießen. Was den Platzhalter betrifft, könntest du bswp. Template-Literale benutzen. Das Grundgerüst dafür könnte so aussehen:

                async function readAndSend () {
                    const json = await fsPromises.readFile(path);
                    const html = `<html>… <script type="text/json">${json}</script> …</html>`;
                    response.send(html);
                }
                readAndSend();
                
                1. Hallo,

                  Benutz lieber fsPromises um Dateien zu lesen, damit kannst du den Code synchron aussehen lassen und dennoch die Vorteile von non-blocking IO genießen.

                  Dürfen wir nicht benutzen.

                  Was den Platzhalter betrifft, könntest du bswp. Template-Literale benutzen. Das Grundgerüst dafür könnte so aussehen:

                  Ich weiß gar nicht, was Template-Literale sind. Zudem, nochmal, es soll ein Anfängerprojekt sein. Vorwissen in HTML, CSS, JS, node.js = 2-3 Monate... 😕

                  Pit

                  1. Benutz lieber fsPromises um Dateien zu lesen, damit kannst du den Code synchron aussehen lassen und dennoch die Vorteile von non-blocking IO genießen.

                    Dürfen wir nicht benutzen.

                    Das hab ich nicht gewusst. Mit readFileSync sähe das Beispiel dann so aus:

                    function readAndSend () {
                        const json = fs.readFileSync(path);
                        const html = `<html>… <script type="text/json">${json}</script> …</html>`;
                        response.send(html);
                    }
                    readAndSend();
                    

                    Was den Platzhalter betrifft, könntest du bswp. Template-Literale benutzen. Das Grundgerüst dafür könnte so aussehen:

                    Ich weiß gar nicht, was Template-Literale sind.

                    Ein JavaScript-String mit Platzhaltern. So ein String wird nicht von einfachen oder doppelten Anführungszeichen umschlossen, sondern von Backsticks. Innerhalb des Strings können Platzhalter benutzt werden, zum Beispiel:

                    const name = "World"; // Normaler String
                    const template = `Hello, ${name}!`; // Template-Literal
                    console.log(template); // Ausgabe lautet: Hello, World!
                    

                    Zudem, nochmal, es soll ein Anfängerprojekt sein. Vorwissen in HTML, CSS, JS, node.js = 2-3 Monate... 😕

                    Das verstehe ich, es würde deinem Verständnis aber weniger nützen, wenn ich dir sofort eine Komplettlösung präsentiere und du hättest dann kein Erfolgserlebnis. Deshalb versuch ich nur richtungsweisende Hilfe zu geben.

                    1. Hi unitedPower,

                      Dürfen wir nicht benutzen.

                      Das hab ich nicht gewusst. Mit readFileSync sähe das Beispiel dann so aus:

                      Schon klar.

                      Ein JavaScript-String mit Platzhaltern. So ein String wird nicht von einfachen oder doppelten Anführungszeichen umschlossen, sondern von Backsticks. Innerhalb des Strings können Platzhalter benutzt werden, zum Beispiel:

                      const name = "World"; // Normaler String
                      const template = `Hello, ${name}!`; // Template-Literal
                      console.log(template); // Ausgabe lautet: Hello, World!
                      

                      Ah, klasse Erklärung, danke!

                      Zudem, nochmal, es soll ein Anfängerprojekt sein. Vorwissen in HTML, CSS, JS, node.js = 2-3 Monate... 😕

                      Das verstehe ich, es würde deinem Verständnis aber weniger nützen, wenn ich dir sofort eine Komplettlösung präsentiere und du hättest dann kein Erfolgserlebnis. Deshalb versuch ich nur richtungsweisende Hilfe zu geben.

                      Du, eine Komplettlösung könnte ich schon erhalten, wenns mir darum ginge, also Richtung weisen ist vollkommen in Ordnung und zudem sehr nett.

                      Warum ich diesen satz schreibe, hat einen anderen hintergrund: Ich empfinde das Projekt (wovon ich jetzt ja nur 1 kleine Teilaufgabe skizziert habe) und die Themenvielfalt als völlig überzogen für Webtechnologie-Anfänger mit einem Wissenstand von 2-3 Monaten.

                      Pit

              2. hi,

                Prinzipiell glaube ich auch, dass Routing über Parameter sinvoller ist.

                Das ist ein Trugschluss. Weil die Namen der Parameter dann für alle URLs gelten, also nicht mehr URL-spezifisch sind. Es wären dann bestimmte Parameter für ganz bestimmte Aktionen/Routen reserviert und wären dann für jeden URL zu kontrollieren.

                Und jetzt stell Dir einmal vor, eine neue Anwendung wäre einzustellen. Für diese Anwendung, die parametergesteuert ist, wären die Namen der Parameter festzulegen. Wie soll das verwaltet werden? Da sind Konflikte und Abhängigkeiten vorprogrammiert, das ist nicht mehr beherrschbar.

                Von daher ist es besser, Routen über einen statischen Teil (/foo.html wäre der statische Anteil) und dynamische Anteile (Parameter) zu organisieren. So könnte eine Anwendung auf /foo.html mit den Parametern bar, action und boo gesteuert werden und wenn sich Parameter mit denselben Namen für einen andere Anwendung auf einem anderen URL anbieten ist das überhaupt kein Problem, das bleibt schön überschaubar.

                Noch komplizierter wird es, wenn außer Parametern im URL oder STDIN noch bestimmte Header und verschiedene Requestmethoden sowie Cookies hinzukommen. Und die kommen mit Sicherheit hinzu, wenn Ajax hinzukommt oder weitere Webservices. Wenn Dein bisheriges Routing nur über Parameter erfolgt, bist Du da sehr schnell in einer Sackgasse, schneller als Dir lieb ist.

                MfG

                1. hi,

                  Prinzipiell glaube ich auch, dass Routing über Parameter sinvoller ist.

                  Als Ergänzung zu meinen Ausführungen über den statischen und dynamischen Anteil einer Route:

                  Ebenfalls statisch sind, neben dem URL/path der Name der Domäne bzw. Subdomäne, das Schema (http, https) nach denen zu routen ist. Hinzu kommen Kriterien zur Content-Negotiation wie z.B. die im Request bevorzugte Sprache und Informationen darüber, ob ein Login vorliegt (Cookie, Session) bzw. wer da angemeldet ist oder nicht (user/group).

                  Das Routen über Parameter macht also nur einen Anteil an einer Route aus, ist also nicht das Einzige Kriterium.

                  MfG

      2. Tach!

        Routing-Tabelle: Hast Du mal ein Beispiel für mich?

        Wenn du mit Express arbeitest, definierst du dir das Routing in der dir bereits bekannten Weise, beziehungsweise so, wie es dokumentiert ist. Wie man das anderswo machen würde, ist dabei nicht sonderlich zielführend.

        dedlfix.

        1. Hi dedlfix,

          Wenn du mit Express arbeitest, definierst du dir das Routing in der dir bereits bekannten Weise, beziehungsweise so, wie es dokumentiert ist. Wie man das anderswo machen würde, ist dabei nicht sonderlich zielführend.

          Ich arbeite mit Express, danke.

          Pit

    2. Nun, stell Dir doch einmal vor, Du würdest das für alle möglichen Seiten so machen, egal ob das jetzt 20 sind oder 1000.

      Dann würde Dein Programm bei jedem Request sämtlichen Code für alle diese Seiten compilieren und das, obwohl der Request nur auf eine von diesen Seiten erfolgt!

      Bei CGI-Anwendungen hättest du Recht, node-Applikationen funktionieren aber nach einem anderen Prinzip.

      Die Frage ob das sinnvoll ist, beantwortet sich von selbst. Und die Lösung hierzu heißt: Routing-Table.

      Die Routing-Tabelle gibt es auch in diesem Beispiel, sie wird aber intern von express verwaltet und ist nur indirekt über eine Schnittstelle ansprechbar.

      1. Nun, stell Dir doch einmal vor, Du würdest das für alle möglichen Seiten so machen, egal ob das jetzt 20 sind oder 1000.

        Dann würde Dein Programm bei jedem Request sämtlichen Code für alle diese Seiten compilieren und das, obwohl der Request nur auf eine von diesen Seiten erfolgt!

        Bei CGI-Anwendungen hättest du Recht, node-Applikationen funktionieren aber nach einem anderen Prinzip.

        Das spricht ja erst recht dafür, für Routen einen statischen Teil vorzuhalten und diesem vom Code zu trennen, der dann ebenfalls statisch ist und bereits beim Hochfahren des Webservers kompiliert wird.

        MfG

        1. Das spricht ja erst recht dafür, für Routen einen statischen Teil vorzuhalten und diesem vom Code zu trennen, der dann ebenfalls statisch ist und bereits beim Hochfahren des Webservers kompiliert wird.

          Das ist bereits so, der Router wird von Express einmalig initialisiert, wenn der Node-Prozess gestartet wird.