it-swarm.com.de

res.sendfile in Node Express mit Weitergabe von Daten

Gibt es eine Möglichkeit, aus einer Node.JS-Anwendung mit einem der folgenden Befehle zu einer HTML-Datei umzuleiten: res.sendFile of express und JSON-Daten an die HTML-Datei weiterleiten? 

20
user3393991

Sie erhalten eine Antwort von einer gegebenen Anfrage. Sie können entweder mehrere Dinge zu einer Antwort zusammenfassen oder vom Client separate Anforderungen anfordern, um separate Dinge zu erhalten.

Wenn Sie versuchen, eine HTML-Datei zu übernehmen und durch Einfügen von JSON zu modifizieren, können Sie nicht einfach res.sendFile() verwenden, da dies nur eine Datei von der Festplatte oder dem Cache liest und direkt als Antwort überträgt bietet keine Möglichkeit, es zu ändern. 

Die üblichere Methode hierfür ist die Verwendung eines Vorlagensystems, mit dem Sie Elemente in eine HTML-Datei einfügen können (wobei normalerweise spezielle Tags durch Ihre eigenen Daten ersetzt werden). Es gibt buchstäblich Hunderte von Schablonensystemen und viele, die node.js unterstützen. Übliche Optionen für node.js sind Jade (Pug), Lenker, Glut, Staub, EJS, Schnurrbart.

Wenn Sie es wirklich wollten, können Sie die HTML-Datei in den Arbeitsspeicher lesen, eine .replace()-Operation verwenden, um Ihre eigenen Daten einzufügen, und dann res.send() die resultierende geänderte Datei.

10
jfriend00

Ich weiß, dass dies zu spät ist, aber ich wollte eine Lösung anbieten, die sonst niemand bereitgestellt hat. Mit dieser Lösung kann eine Datei an die Antwort gestreamt werden, während Sie weiterhin den Inhalt ändern können, ohne dass ein Templating Engine erforderlich ist oder die gesamte Datei im Arbeitsspeicher zwischengespeichert wird.

Wenn Sie sich nicht für "warum" interessieren, springen Sie nach unten.

Lassen Sie mich zuerst beschreiben, warum res.sendFile für diejenigen, die es nicht wissen, so wünschenswert ist. Da Node ein einzelner Thread ist, werden viele kleine Aufgaben nacheinander ausgeführt. Dazu gehört das Lesen aus dem Dateisystem und das Beantworten einer http-Anforderung. Zu keinem Zeitpunkt stoppt Node einfach seine Arbeit und liest eine komplette Datei aus dem Dateisystem. Es wird etwas lesen, etwas anderes tun, etwas mehr lesen, etwas anderes tun. Das Gleiche gilt für die Beantwortung einer http-Anfrage und der meisten anderen Operationen in Node (es sei denn, Sie verwenden explizit die sync-Version einer Operation - wie etwa readFileSync -). Tun Sie dies nicht, wenn Sie ihm helfen können, ernsthaft, nicht - es ist egoistisch ). 

Stellen Sie sich ein Szenario vor, in dem 10 Benutzer dieselbe Datei anfordern. Das ineffiziente Vorgehen wäre, die gesamte Datei in den Speicher zu laden und die Datei dann mit res.send() zu senden. Obwohl es sich um dieselbe Datei handelt, wird die Datei zehnmal in den Speicher geladen, bevor sie an den Browser gesendet wird. Der Speicherbereiniger müsste dann nach jeder Anforderung dieses Durcheinander aufräumen. Der Code wäre unschuldig so geschrieben:

app.use('/index.html', (req, res) => {
   fs.readFile('../public/index.html', (err, data) => {
      res.send(data.toString());
   });
});

Das scheint richtig zu sein und funktioniert, aber es ist furchtbar ineffizient. Da wir wissen, dass Node Dinge in kleinen Abschnitten erledigt, ist es das Beste, die kleinen Datenabschnitte an den Browser zu senden, während sie aus dem Dateisystem gelesen werden. Die Chunks werden nie im Speicher abgelegt, und Ihr Server kann jetzt um ein Vielfaches mehr Datenverkehr verarbeiten. Dieses Konzept wird als Streaming bezeichnet. Dies ist, was res.sendFile tut - es strömt die Datei direkt aus dem Dateisystem zum Benutzer und hält den Speicher für wichtigere Dinge frei. So sieht es aus, wenn Sie es manuell machen würden:

app.use('/index.html', (req, res) => {
    fs.createReadStream('../public/index.html')
    .pipe(res);
});

Lösung

Wenn Sie eine Datei weiter an den Benutzer streamen möchten, während Sie geringfügige Änderungen daran vornehmen, ist diese Lösung für Sie. Bitte beachten Sie, dass dies kein Ersatz für eine Templating Engine ist, sondern eher dazu verwendet werden soll, um kleine Änderungen an einer Datei vorzunehmen, während sie gestreamt wird. Mit dem folgenden Code wird ein kleines Skript-Tag mit Daten an den Hauptteil einer HTML-Seite angehängt. Außerdem wird gezeigt, wie einem HTTP-Antwortstream Inhalt hinzugefügt oder angehängt wird:

const Transform = require('stream').Transform;
const parser = new Transform();
parser._transform = function(data, encoding, done) {
  const str = data.toString().replace('</body>', '<script>var data = {"foo": "bar"};</script></body>');
  this.Push(str);
  done();
};

// app creation code removed for brevity

app.use('/index.html', (req, res) => {
    res.write('<!-- Begin stream -->\n');
    fs
    .createReadStream('../public/index.html')
    .pipe(parser)
    .on('end', () => {
        res.write('\n<!-- End stream -->')
    }).pipe(res);
});
25
Ryan Wheale

Nun, es ist ein bisschen alt, aber ich habe keine ausreichende Antwort gesehen, außer "warum nicht". Sie haben keine Möglichkeit, Parameter IN statische Datei zu übergeben. Und das ist ganz einfach. Betrachten Sie folgenden Code in Ihrem Origin (mit Express):

    let data = fs.readFileSync('yourPage.html');
    if(data)
    res.send(data.replace('param1Place','uniqueData'));
    //else - 404

Setzen Sie zum Beispiel einfach ein Cookie in yourPage.html .

    <script>
    var date = new Date();
    document.cookie = "yourCookieName='param1Place';" + 
    date.setTime(date.getTime() + 3600) + ";path=/";
    </script>

Und Sie können den Inhalt von uniqueData ganz einfach aus IhremCookieName ziehen, wo immer Sie möchten

2
user6476673

Sie haben nur eine Antwort, die Sie vom Server zurücksenden können. Am häufigsten sollten Sie Ihre Datei mit Nunjucks oder Jade auf dem Server vorbereiten. Eine andere Möglichkeit besteht darin, die Datei auf dem Client zu rendern und anschließend Javascript zu verwenden, um einen Ajax-Aufruf an den Server zu tätigen, um zusätzliche Daten abzurufen. Ich nehme an, Sie könnten auch einige Daten in einem Cookie setzen und diese dann auf der Clientseite auch über Javascript lesen.

1
Robert Moskal

(Es sei denn, Sie möchten die HTML-Datei vorbereiten, um die Json-Daten in ein Skript-Tag einzufügen). Sie müssen einen Api-Endpunkt für das Senden der Daten an die Seite freigeben und auf der Seite über eine Funktion verfügen, um darauf zuzugreifen. zum Beispiel,

// send the html
app.get('/', (req, res) => res.sendFile('index'));

// send json data
app.get('/data', (req, res) => res.json(data));

Auf der Clientseite können Sie jetzt eine Anforderung erstellen, um auf diesen Endpunkt zuzugreifen

function get() {
  return new Promise((resolve, reject) => {
    var req = new XMLHttpRequest();
    req.open('GET', '/data');
    req.onload = () => resolve(req.response);
  });
}           
 // then to get the data, call the function

get().then((data) => {
  var parsed = JSON.parse(data);
  // do something with the data
});

BEARBEITEN:

Pfeilfunktionen funktionieren also wahrscheinlich noch nicht clientseitig. Stellen Sie sicher, dass Sie sie durch function () {} in Ihrem Code ersetzen

0
Jonah Williams

Warum lesen Sie nicht einfach die Datei, wenden Transformationen an und richten die Route dann im Callback ein?

fs.readFile(appPath, (err, html) => {
   let htmlPlusData = html.toString().replace("DATA", JSON.stringify(data));

   app.get('/', (req, res) => {
       res.send(htmlPlusData);
   });
});

Beachten Sie, dass Sie data nicht dynamisch ändern können. Sie müssen die Knoteninstanz neu starten.

0
Brad