POST-Formular und Auswertung | Session und Cookies |
Formidable installieren
Für das Hochladen von Bildern hilft die zusätzliche Bibliothek formidable. Sie sorgt dafür, dass die in den Inputs vom Typ File angegebenen Datei hochgeladen werden. Diese muss explizit installiert werden, typischerweise per npm:npm install formidableNach dem Aufruf von formidable landen die Dateien unter einem fortlaufenden Namen in einem temporären Verzeichnis. Nachdem sie dort angekommen sind, müssen sie in das eigentliche Zielverzeichnis verschoben werden und ihren ursprünglichen Namen wieder erhalten.
Danach wird eine Seite mit dem hochgeladenen Bild angezeigt. Dazu wird die HTML-IMG-Tag verwendet. Das Nachladen eines Bildes führt aber zu einem erneuten HTTP-GET-Aufruf führt, den der Server natürlich beantworten muss.
Beispielprogramm
Das Programm soll ein minimales Eingabeformular anbieten. Damit soll ein Bild hochgeladen und ein Titel vergeben werden. Auf dem nächsten Bildschirm wird das Bild und der Titel angezeigt.Alle drei Aktionen geschehen im gleichen Server. Die Aktionen werden über die URL-Pfade unterschieden. Dies wird häufig mit Express erledigt. In diesem Beispiel wird eine einfache Fallunterscheidung für das Routing verwendet und je nach URL-Pfad eine eigene Funktion aufgerufen.
var http = require('http'); var formidable = require('formidable'); var fs = require('fs'); const path = require("path"); http.createServer(function (req, res) { if (req.url == '/') { return showUploadForm(res); } else if (req.url == '/fileupload') { return loadFileAndShow(req, res); } else if (req.url.match('/images/*')) { return sendImage(req, res); } }).listen(8080);
Laden des Formulars
Anfragen auf das Wurzelverzeichnis führen dazu, dass ein HTML-Formular auf dem Browser erscheint.- Die Form enthält ein einfaches EDIT-Input für die Eingabe des Titels.
- Darüber hinaus gibt es ein FILE-Input, das die Auswahl einer Datei ermöglicht und anschließend den ausgewählten Dateinamen enthält.
- Die FORM enthält als ACTION den Pfad /fileupload, wodurch das Hochladen der Datei ausgelöst wird.
function showUploadForm(res) { res.writeHead(200, {'Content-Type': 'text/html'}); res.write('<form action="fileupload" method="post" enctype="multipart/form-data">'); res.write('Bild: <input type="file" name="filetoupload"><br>'); res.write('Titel: <input type="edit" name="titel"><br>'); res.write('<input type="submit">'); res.write('</form>'); return res.end(); }Die direkte Ausgabe der HTML-Zeilen ist bei größeren Formularen natürlich etwas umständlich. Da der HTML-Code nicht dynamisch verändert wird, ist es bei umfangreicherem HTML-Code sinnvoller, diesen in einer eigenständigen HTML-Datei abzulegen und die HTML-Datei an den Aufrufer zu senden.
Hochladen der Datei
Durch die ACTION im Formular wird eine POST-Anfrage auf /filetoupload ausgelöst. Das Rahmenprogramm führt daraufhin in die Funktion loadFileAndShow, die hier vorgestellt wird.Gleich zu Anfang wird formidable aufgerufen, das zuvor mit require eingebunden wurde. Über deren Parameter wird unter anderem der Pfad festgelegt, in den die hochgeladenen Dateien zunächst abgelegt werden sollen.
var formidable = require('formidable'); // ... function loadFileAndShow(req, res) { const form = formidable( { multiples: false, uploadDir: __dirname, keepExtensions: true });
Als Parameter wird ein JSON-Objekt übergeben, das verschiedene Einstellungen festmacht.
- So können durch den booleschen Wert multiples mehrere Dateien auf einen Schlag hochgeladen werden.
- Mit keepExtensions wird die Dateierweiterung beibehalten.
- uploadDir gibt an, in welchem Verzeichnis die Dateien nach dem
Hochladen landen sollen.
Dieser Ort (hier __dirname) muss auf demselben Dateisystem wie der spätere Lagerort der Dateien liegen, weil der Aufruf von fs.rename nur innerhalb eines Dateisystems funktioniert.
Hat die Umbenennung und damit die Verschiebung funktioniert, kann ein neues HTML-Dokument zurückgesandt werden, indem das Bild und der Titel angezeigt wird.
function loadFileAndShow(req, res) { const form = formidable({ multiples: false, uploadDir: __dirname, // vorläufiger Ort des Uploads keepExtensions: true }); form.parse(req, function(err, fields, files) { if (err) { // Ein Problem? Melde das dem Aufrufer res.writeHead(400, { 'Content-Type': 'text/plain' }); res.end(""+(err)); return; } if (files.filetoupload) { // Es ist etwas hochgeladen worden. Die Datei in das Zielverzeichnis bringen const imageTarget = path.join(__dirname, "images", files.filetoupload.originalFilename); imageFile = path.join("images", files.filetoupload.originalFilename); fs.rename(files.filetoupload.filepath, imageTarget, function(err) { if (err) { // Ist das Verschieben schiefgegangen? res.writeHead(400, { 'Content-Type': 'text/plain' }); res.end(""+(err)); return; } res.writeHead(200, {'Content-Type': 'text/html'}); res.write('<img src="'+ imageFile+'"><br>'); // Achtung: <img src="xxxx"> führt zu einem weiteren HTTP-GET res.write('Titel: '+fields.titel+'<br>'); res.end(); return; }); } }); }
Anzeigen der Bilder
Der IMG-Tag von HTML führt zu einer neuen HTTP-GET-Anfrage. Aus diesem Grund ist es clever, die Bilder in einem eigenen Verzeichnis zu lagern. Das erleichter das Routing. So wird die hier vorgestellte Funktion sendImage aufgerufen, wenn die URL /image angefragt wurde.Zum Senden der Bilddatei wird fs.readFile eingesetzt.
function sendImage(req, res) { // Hier landen die <img src=/images/xxx> - GET-Anfragen fs.readFile(path.join(__dirname, req.url), function(error, data) { if (data) { res.write(data); res.end(); } else { // error: Die Datei gibt es wohl nicht oder ist defekt res.writeHead(404); res.write(error.toString()); res.end("\nDateifehler"); } }); }