Update 2016
Beispiele mit Express und ohne Express, die tatsächlich funktionieren
Diese Frage ist über 5 Jahre alt, aber jede Antwort hat einige Probleme .
TL; DR
Scrollen Sie nach unten, um Beispiele für ein Bild anzuzeigen:
express.static
express
connect
http
net
Alle Beispiele finden Sie auch auf GitHub: https://github.com/rsp/node-static-http-servers
Testergebnisse sind auf Travis verfügbar: https://travis-ci.org/rsp/node-static-http-servers
Einführung
Nach über 5 Jahren, seit diese Frage gestellt wurde, gibt es nur eine richtige Antwort von Generalhenry, aber obwohl diese Antwort keine Probleme mit dem Code hat, scheint sie einige Probleme mit dem Empfang zu haben . Es wurde kommentiert, dass es "nicht viel anderes erklärt, als sich auf jemand anderen zu verlassen, um die Arbeit zu erledigen", und die Tatsache, wie viele Leute diesen Kommentar abgegeben haben, zeigt deutlich, dass viele Dinge einer Klärung bedürfen.
Zuallererst ist eine gute Antwort auf "Wie man Bilder mit Node.js bereitstellt" nicht, einen statischen Dateiserver von Grund auf neu zu implementieren und es schlecht zu machen. Eine gute Antwort ist die Verwendung eines Moduls wie Express, das die Aufgabe korrekt erledigt .
Bei der Beantwortung von Kommentaren, die besagen, dass die Verwendung von Express "nicht viel anderes erklärt, als sich auf eine andere Person zu verlassen, um die Arbeit zu erledigen" , sollte beachtet werden, dass die Verwendung des http
Moduls bereits auf eine andere Person angewiesen ist, um die Arbeit zu erledigen. Wenn sich jemand nicht auf jemanden verlassen möchte, um die Arbeit zu erledigen, sollten stattdessen mindestens rohe TCP-Sockets verwendet werden - was ich in einem meiner folgenden Beispiele tue.
Ein ernsteres Problem ist , dass alle Antworten hier , dass die Verwendung http
Modul sind gebrochen . Sie führen Rennbedingungen , unsicheren Weg Auflösung , die führen Path Traversal Schwachstelle , blockierte I / O , die vollständig wird keine gleichzeitigen Anfragen zu bedienen scheitern bei alle und anderen subtilen Problemen - sie werden als Beispiele für völlig gebrochen , was die Frage bezieht , und Dennoch verwenden sie bereits die vom http
Modul bereitgestellte Abstraktion anstelle von TCP-Sockets, sodass sie nicht einmal alles von Grund auf neu machen, wie sie behaupten.
Wenn die Frage lautete: "Wie wird ein statischer Dateiserver als Lernübung von Grund auf neu implementiert?", Sollten auf jeden Fall Antworten dazu veröffentlicht werden - aber selbst dann sollten wir erwarten, dass sie zumindest korrekt sind . Es ist auch nicht unangemessen anzunehmen, dass jemand, der ein Bild bereitstellen möchte, in Zukunft möglicherweise mehr Bilder bereitstellen möchte, sodass man argumentieren könnte, dass das Schreiben eines bestimmten benutzerdefinierten statischen Dateiservers, der nur eine einzelne Datei mit fest codiertem Pfad bereitstellen kann, dies ist etwas kurzsichtig. Es ist schwer vorstellbar, dass jeder, der nach einer Antwort auf die Frage sucht, wie ein Bild bereitgestellt werden soll, sich mit einer Lösung zufrieden gibt, die nur ein einzelnes Bild anstelle einer allgemeinen Lösung für die Bereitstellung eines Bildes bereitstellt.
Kurz gesagt, die Frage ist, wie ein Image bereitgestellt werden kann, und eine Antwort darauf besteht darin, ein geeignetes Modul zu verwenden, um dies auf sichere, vorformende und zuverlässige Weise zu tun, das lesbar, wartbar und zukunftssicher ist und dabei die Best Practice des professionellen Knotens verwendet Entwicklung. Ich stimme jedoch zu, dass eine großartige Ergänzung zu einer solchen Antwort darin besteht, die gleiche Funktionalität manuell zu implementieren, aber leider ist jeder Versuch, dies zu tun, bisher gescheitert. Und deshalb habe ich einige neue Beispiele geschrieben.
Nach dieser kurzen Einführung sind hier meine fünf Beispiele, die die Arbeit auf 5 verschiedenen Abstraktionsebenen erledigen.
Minimale Funktionalität
Jedes Beispiel public
liefert Dateien aus dem Verzeichnis und unterstützt die Mindestfunktionalität von:
- MIME-Typen für die meisten gängigen Dateien
- dient HTML, JS, CSS, Klartext und Bildern
- dient
index.html
als Standardverzeichnisindex
- antwortet mit Fehlercodes für fehlende Dateien
- Keine Schwachstellen bei der Pfadüberquerung
- Keine Rennbedingungen beim Lesen von Dateien
Ich habe jede Version auf den Knotenversionen 4, 5, 6 und 7 getestet.
express.static
Diese Version verwendet die express.static
integrierte Middleware des express
Moduls.
Dieses Beispiel bietet die meisten Funktionen und die geringste Menge an Code.
var path = require('path');
var express = require('express');
var app = express();
var dir = path.join(__dirname, 'public');
app.use(express.static(dir));
app.listen(3000, function () {
console.log('Listening on http://localhost:3000/');
});
express
Diese Version verwendet das express
Modul, jedoch ohne express.static
Middleware. Das Bereitstellen statischer Dateien wird als einzelner Routenhandler mithilfe von Streams implementiert.
Dieses Beispiel enthält einfache Gegenmaßnahmen zur Pfadüberquerung und unterstützt eine begrenzte Anzahl der gängigsten MIME-Typen.
var path = require('path');
var express = require('express');
var app = express();
var fs = require('fs');
var dir = path.join(__dirname, 'public');
var mime = {
html: 'text/html',
txt: 'text/plain',
css: 'text/css',
gif: 'image/gif',
jpg: 'image/jpeg',
png: 'image/png',
svg: 'image/svg+xml',
js: 'application/javascript'
};
app.get('*', function (req, res) {
var file = path.join(dir, req.path.replace(/\/$/, '/index.html'));
if (file.indexOf(dir + path.sep) !== 0) {
return res.status(403).end('Forbidden');
}
var type = mime[path.extname(file).slice(1)] || 'text/plain';
var s = fs.createReadStream(file);
s.on('open', function () {
res.set('Content-Type', type);
s.pipe(res);
});
s.on('error', function () {
res.set('Content-Type', 'text/plain');
res.status(404).end('Not found');
});
});
app.listen(3000, function () {
console.log('Listening on http://localhost:3000/');
});
connect
Diese Version verwendet das connect
Modul, das eine Abstraktionsebene niedriger als ist express
.
Dieses Beispiel hat eine ähnliche Funktionalität wie die express
Version, verwendet jedoch APIs mit etwas niedrigerem Hebel.
var path = require('path');
var connect = require('connect');
var app = connect();
var fs = require('fs');
var dir = path.join(__dirname, 'public');
var mime = {
html: 'text/html',
txt: 'text/plain',
css: 'text/css',
gif: 'image/gif',
jpg: 'image/jpeg',
png: 'image/png',
svg: 'image/svg+xml',
js: 'application/javascript'
};
app.use(function (req, res) {
var reqpath = req.url.toString().split('?')[0];
if (req.method !== 'GET') {
res.statusCode = 501;
res.setHeader('Content-Type', 'text/plain');
return res.end('Method not implemented');
}
var file = path.join(dir, reqpath.replace(/\/$/, '/index.html'));
if (file.indexOf(dir + path.sep) !== 0) {
res.statusCode = 403;
res.setHeader('Content-Type', 'text/plain');
return res.end('Forbidden');
}
var type = mime[path.extname(file).slice(1)] || 'text/plain';
var s = fs.createReadStream(file);
s.on('open', function () {
res.setHeader('Content-Type', type);
s.pipe(res);
});
s.on('error', function () {
res.setHeader('Content-Type', 'text/plain');
res.statusCode = 404;
res.end('Not found');
});
});
app.listen(3000, function () {
console.log('Listening on http://localhost:3000/');
});
http
Diese Version verwendet das http
Modul, das die niedrigste API für HTTP in Node ist.
Dieses Beispiel hat ähnliche Funktionen wie die connect
Version, verwendet jedoch noch mehr APIs auf niedrigerer Ebene.
var path = require('path');
var http = require('http');
var fs = require('fs');
var dir = path.join(__dirname, 'public');
var mime = {
html: 'text/html',
txt: 'text/plain',
css: 'text/css',
gif: 'image/gif',
jpg: 'image/jpeg',
png: 'image/png',
svg: 'image/svg+xml',
js: 'application/javascript'
};
var server = http.createServer(function (req, res) {
var reqpath = req.url.toString().split('?')[0];
if (req.method !== 'GET') {
res.statusCode = 501;
res.setHeader('Content-Type', 'text/plain');
return res.end('Method not implemented');
}
var file = path.join(dir, reqpath.replace(/\/$/, '/index.html'));
if (file.indexOf(dir + path.sep) !== 0) {
res.statusCode = 403;
res.setHeader('Content-Type', 'text/plain');
return res.end('Forbidden');
}
var type = mime[path.extname(file).slice(1)] || 'text/plain';
var s = fs.createReadStream(file);
s.on('open', function () {
res.setHeader('Content-Type', type);
s.pipe(res);
});
s.on('error', function () {
res.setHeader('Content-Type', 'text/plain');
res.statusCode = 404;
res.end('Not found');
});
});
server.listen(3000, function () {
console.log('Listening on http://localhost:3000/');
});
net
Diese Version verwendet das net
Modul, das die niedrigste API für TCP-Sockets in Node ist.
Dieses Beispiel enthält einige Funktionen der http
Version, aber das minimale und unvollständige HTTP-Protokoll wurde von Grund auf neu implementiert. Da es keine Chunked-Codierung unterstützt, werden die Dateien in den Speicher geladen, bevor sie bereitgestellt werden, um die Größe zu ermitteln, bevor eine Antwort gesendet wird, da das Einsetzen der Dateien und das anschließende Laden eine Race-Bedingung einführen würde.
var path = require('path');
var net = require('net');
var fs = require('fs');
var dir = path.join(__dirname, 'public');
var mime = {
html: 'text/html',
txt: 'text/plain',
css: 'text/css',
gif: 'image/gif',
jpg: 'image/jpeg',
png: 'image/png',
svg: 'image/svg+xml',
js: 'application/javascript'
};
var server = net.createServer(function (con) {
var input = '';
con.on('data', function (data) {
input += data;
if (input.match(/\n\r?\n\r?/)) {
var line = input.split(/\n/)[0].split(' ');
var method = line[0], url = line[1], pro = line[2];
var reqpath = url.toString().split('?')[0];
if (method !== 'GET') {
var body = 'Method not implemented';
con.write('HTTP/1.1 501 Not Implemented\n');
con.write('Content-Type: text/plain\n');
con.write('Content-Length: '+body.length+'\n\n');
con.write(body);
con.destroy();
return;
}
var file = path.join(dir, reqpath.replace(/\/$/, '/index.html'));
if (file.indexOf(dir + path.sep) !== 0) {
var body = 'Forbidden';
con.write('HTTP/1.1 403 Forbidden\n');
con.write('Content-Type: text/plain\n');
con.write('Content-Length: '+body.length+'\n\n');
con.write(body);
con.destroy();
return;
}
var type = mime[path.extname(file).slice(1)] || 'text/plain';
var s = fs.readFile(file, function (err, data) {
if (err) {
var body = 'Not Found';
con.write('HTTP/1.1 404 Not Found\n');
con.write('Content-Type: text/plain\n');
con.write('Content-Length: '+body.length+'\n\n');
con.write(body);
con.destroy();
} else {
con.write('HTTP/1.1 200 OK\n');
con.write('Content-Type: '+type+'\n');
con.write('Content-Length: '+data.byteLength+'\n\n');
con.write(data);
con.destroy();
}
});
}
});
});
server.listen(3000, function () {
console.log('Listening on http://localhost:3000/');
});
Beispiele herunterladen
Ich habe alle Beispiele mit mehr Erklärungen auf GitHub gepostet.
Beispiele mit express.static
, express
, connect
, http
und net
:
Andere Projekte, die nur Folgendes verwenden express.static
:
Tests
Testergebnisse sind auf Travis verfügbar:
Alles wird auf den Knotenversionen 4, 5, 6 und 7 getestet.
Siehe auch
Andere verwandte Antworten: