In diesem Artikel werden hauptsächlich Beispiele für tatsächliche statische Knotendateiserver vorgestellt. Jetzt teile ich sie mit Ihnen und gebe ihnen eine Referenz.
In diesem Artikel werden hauptsächlich Beispiele für tatsächliche statische Knotendateiserver vorgestellt und mit allen geteilt. Die Details sind wie folgt:
Unterstützte Funktionen:
Statische Dateien lesen
kann beim Zugriff auf das Verzeichnis automatisch die folgende index.html-Datei finden. Wenn keine index.html vorhanden ist, wird die Dateiliste aufgelistet
MIME-Typ-Unterstützung
Cache-Unterstützung/-Steuerung
Unterstützung der GZIP-Komprimierung
Bereichsunterstützung, Fortsetzung ab Haltepunkt Pass
Globale Befehlsausführung
Unterprozessausführung
1 . Erstellen Sie einen Dienst zum Lesen statischer Dateien.
führt zunächst das http-Modul ein, erstellt einen Server und lauscht auf den Konfigurationsport:
const http = require('http'); const server = http.createServer(); // 监听请求 server.on('request', request.bind(this)); server.listen(config.port, () => { console.log(`静态文件服务启动成功, 访问localhost:${config.port}`); });
Schreiben Sie eine FN speziell für die Verarbeitung von Anforderungen und die Rückgabe statischer Dateien. Das URL-Modul erhält den Pfad:
const url = require('url'); const fs = require('fs'); function request(req, res) { const { pathname } = url.parse(req.url); // 访问路径 const filepath = path.join(config.root, pathname); // 文件路径 fs.createReadStream(filepath).pipe(res); // 读取文件,并响应 }
Unterstützung bei der Suche nach index.html:
if (pathname === '/') { const rootPath = path.join(config.root, 'index.html'); try{ const indexStat = fs.statSync(rootPath); if (indexStat) { filepath = rootPath; } } catch(e) { } }
Listen Sie beim Zugriff auf das Verzeichnis das Dateiverzeichnis auf:
fs.stat(filepath, (err, stats) => { if (err) { res.end('not found'); return; } if (stats.isDirectory()) { let files = fs.readdirSync(filepath); files = files.map(file => ({ name: file, url: path.join(pathname, file) })); let html = this.list()({ title: pathname, files }); res.setHeader('Content-Type', 'text/html'); res.end(html); } }
HTML-Vorlage:
function list() { let tmpl = fs.readFileSync(path.resolve(__dirname, 'template', 'list.html'), 'utf8'); return handlebars.compile(tmpl); }
2. MIME-Typ-Unterstützung
Verwenden Sie das MIME-Modul, um den Dateityp abzurufen und die Kodierung festzulegen:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>{{title}}</title> </head> <body> <h1>hope-server静态文件服务器</h1> <ul> {{#each files}} <li> <a href={{url}}>{{name}}</a> </li> {{/each}} </ul> </body> </html>
3. Cache-Unterstützung
HTTP-Protokoll-Cache:
Cache-Kontrolle: http1.1-Inhalte, teilen Sie den Kunden mit, wie der Client Daten zwischenspeichert und welche Regeln gelten
private Clients können zwischenspeichern
Öffentlicher Client und Proxyserver können zwischenspeichern
max-age=60 Der zwischengespeicherte Inhalt läuft nach 60 Sekunden ab
Nein -cache Sie müssen den Vergleichscache verwenden, um die Daten zu überprüfen und den Quellserver zu einer erneuten Überprüfung zu zwingen.
no-store Alle Inhalte werden nicht zwischengespeichert, und es gibt weder erzwungenes Caching noch Vergleichscaching wird ausgelöst
Läuft ab: http1.0-Inhalt, Cache – Das Steuerelement wird überschrieben und teilt dem Client mit, wann der Cache abläuft
ETag: der Hashwert von Fügen Sie bei der nächsten Anfrage des Clients „if-none-match: etag value“ in den Anforderungsheader ein.
Last-Modified: Zuletzt geändert. Fügen Sie bei der nächsten Anfrage des Clients „if-modified-since“ hinzu : Zuletzt geänderter Wert im Anforderungsheader
res.setHeader('Content-Type', mime.getType(filepath) + ';charset=utf-8');
4. Komprimierung
Der Client sendet den Inhalt über den Anforderungsheader Accept-Encoding: gzip, deflate teilt dem Server mit, welche Komprimierungsformate unterstützt werden. und der Server komprimiert den Inhalt basierend auf den unterstützten Komprimierungsformaten. Wenn der Server dies nicht unterstützt, wird keine Komprimierung durchgeführt.
handleCache(req, res, stats, hash) { // 当资源过期时, 客户端发现上一次请求资源,服务器有发送Last-Modified, 则再次请求时带上if-modified-since const ifModifiedSince = req.headers['if-modified-since']; // 服务器发送了etag,客户端再次请求时用If-None-Match字段来询问是否过期 const ifNoneMatch = req.headers['if-none-match']; // http1.1内容 max-age=30 为强行缓存30秒 30秒内再次请求则用缓存 private 仅客户端缓存,代理服务器不可缓存 res.setHeader('Cache-Control', 'private,max-age=30'); // http1.0内容 作用与Cache-Control一致 告诉客户端什么时间,资源过期 优先级低于Cache-Control res.setHeader('Expires', new Date(Date.now() + 30 * 1000).toGMTString()); // 设置ETag 根据内容生成的hash res.setHeader('ETag', hash); // 设置Last-Modified 文件最后修改时间 const lastModified = stats.ctime.toGMTString(); res.setHeader('Last-Modified', lastModified); // 判断ETag是否过期 if (ifNoneMatch && ifNoneMatch != hash) { return false; } // 判断文件最后修改时间 if (ifModifiedSince && ifModifiedSince != lastModified) { return false; } // 如果存在且相等,走缓存304 if (ifNoneMatch || ifModifiedSince) { res.writeHead(304); res.end(); return true; } else { return false; } }
5. Setzen Sie den Haltepunkt fort
Der Server verwendet den Bereich: Bytes=0-xxx im Anforderungsheader, um zu bestimmen, ob dieser Wert vorhanden und gültig ist , wird nur der angeforderte Teil des Dateiinhalts zurückgegeben, der Antwortstatuscode wird zu 206, was auf Teilinhalt hinweist, und der Inhaltsbereich wird festgelegt. Wenn es ungültig ist, wird der Statuscode 416 zurückgegeben, der angibt, dass der Anforderungsbereich nicht erfüllt werden kann. Wenn der Range-Request-Header nicht enthalten ist, antworten Sie weiterhin wie gewohnt.
getEncoding(req, res) { const acceptEncoding = req.headers['accept-encoding']; // gzip和deflate压缩 if (/\bgzip\b/.test(acceptEncoding)) { res.setHeader('Content-Encoding', 'gzip'); return zlib.createGzip(); } else if (/\bdeflate\b/.test(acceptEncoding)) { res.setHeader('Content-Encoding', 'deflate'); return zlib.createDeflate(); } else { return null; } }
6. Globale Befehlsausführung
implementiert über npm-Link
Erstellen Sie einen Softlink für das npm-Paketverzeichnis und verknüpfen Sie ihn mit {prefix} / lib/node_modules/
Erstellen Sie einen Softlink für die ausführbare Datei (bin) und verknüpfen Sie ihn mit {prefix}/bin/{name}
Der Befehl „npm link“ macht den Befehl „npm package“ global ausführbar, indem Verzeichnisse und ausführbare Dateien verknüpft werden.
Konfiguration in package.json
getStream(req, res, filepath, statObj) { let start = 0; let end = statObj.size - 1; const range = req.headers['range']; if (range) { res.setHeader('Accept-Range', 'bytes'); res.statusCode = 206;//返回整个内容的一块 let result = range.match(/bytes=(\d*)-(\d*)/); if (result) { start = isNaN(result[1]) ? start : parseInt(result[1]); end = isNaN(result[2]) ? end : parseInt(result[2]) - 1; } } return fs.createReadStream(filepath, { start, end }); }
Erstellen Sie eine Bin-Verzeichnis-Hope-Datei unter dem Projekt und verwenden Sie die Yargs-Konfigurationsbefehlszeile, um Parameter zu übergeben
{ bin: { "hope-server": "bin/hope" } }
7. Führen Sie den Unterprozess aus
Erreicht durch spawn
index.js
// 告诉电脑用node运行我的文件 #! /usr/bin/env node const yargs = require('yargs'); const init = require('../src/index.js'); const argv = yargs.option('d', { alias: 'root', demand: 'false', type: 'string', default: process.cwd(), description: '静态文件根目录' }).option('o', { alias: 'host', demand: 'false', default: 'localhost', type: 'string', description: '配置监听的主机' }).option('p', { alias: 'port', demand: 'false', type: 'number', default: 8080, description: '配置端口号' }).option('c', { alias: 'child', demand: 'false', type: 'boolean', default: false, description: '是否子进程运行' }) .usage('hope-server [options]') .example( 'hope-server -d / -p 9090 -o localhost', '在本机的9090端口上监听客户端的请求' ).help('h').argv; // 启动服务 init(argv);
8. Quellcode und Tests
Quellcode-Adresse: Hope-Server
const { spawn } = require('child_process'); const Server = require('./hope'); function init(argv) { // 如果配置为子进程开启服务 if (argv.child) { //子进程启动服务 const child = spawn('node', ['hope.js', JSON.stringify(argv)], { cwd: __dirname, detached: true, stdio: 'inherit' }); //后台运行 child.unref(); //退出主线程,让子线程单独运行 process.exit(0); } else { const server = new Server(argv); server.start(); } } module.exports = init; hope.js if (process.argv[2] && process.argv[2].startsWith('{')) { const argv = JSON.parse(process.argv[2]); const server = new Hope(argv); server.start(); }
Geben Sie ein beliebiges Verzeichnis ein
rrreeDas Obige habe ich für alle zusammengestellt. Ich hoffe, dass es in Zukunft für alle hilfreich sein wird.
Verwandte Artikel:
So implementieren Sie die String-Verkettung in JS (Erweitern von String.prototype.format)
Verwenden von ES6 Lösen Sie den Speicher Leckproblem durch WeakMap (ausführliches Tutorial)
So implementieren Sie zufälligen Umschaltcode der WeChat-ID über JavaScript (ausführliches Tutorial)
Das obige ist der detaillierte Inhalt vonBeispielcode für den tatsächlichen statischen Knotendateiserver. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!