Heim > Web-Frontend > js-Tutorial > Hauptteil

Ausführliche Erläuterung der statischen Dateiserverinstanz des Knotens

小云云
Freigeben: 2018-03-12 09:35:00
Original
1265 Leute haben es durchsucht

Dieser Artikel stellt Ihnen hauptsächlich ein Beispiel für einen statischen Knotendateiserver vor. In diesem Artikel werden zunächst seine Funktionen aufgeführt und dann in Form von Code mit Ihnen geteilt.

Unterstützte Funktionen:

  1. Statische Dateien lesen

  2. Beim Zugriff auf das Verzeichnis kann automatisch die folgende index.html-Datei gefunden werden, wenn Wenn keine index.html vorhanden ist, listen Sie die Dateien auf

  3. MIME-Typ-Unterstützung

  4. Cache-Unterstützung/-Steuerung

  5. Unterstützung der GZIP-Komprimierung

  6. Bereichsunterstützung, Haltepunkt-Wiederaufnahme

  7. Globale Befehlsausführung

  8. Unterprozess läuft

1. Erstellen Sie einen Dienst zum Lesen statischer Dateien

Führen Sie zunächst das http-Modul ein, erstellen Sie einen Server und überwachen Sie 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}`);
 });
Nach dem Login kopieren

Schreiben Sie eine FN speziell für die Bearbeitung von Anfragen 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); // 读取文件,并响应
 }
Nach dem Login kopieren

Unterstützt die 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) {
   
  }
 }
Nach dem Login kopieren

Listen Sie beim Zugriff auf das Verzeichnis die Dateien auf. Verzeichnis:

 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);
 }
 }
Nach dem Login kopieren

HTML-Vorlage:

 function list() {
  let tmpl = fs.readFileSync(path.resolve(__dirname, 'template', 'list.html'), 'utf8');
  return handlebars.compile(tmpl);
 }
Nach dem Login kopieren
 <!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>
Nach dem Login kopieren

2.MIME-Typ-Unterstützung

Verwenden Sie das MIME-Modul, um Holen Sie sich den Dateityp und legen Sie die Kodierung fest:

res.setHeader(&#39;Content-Type&#39;, mime.getType(filepath) + &#39;;charset=utf-8&#39;);
Nach dem Login kopieren

3. Cache-Unterstützung

HTTP-Protokoll-Cache:

Cache-Steuerung: http1.1-Inhalt, teilt dem Client mit wie Daten und Regeln zwischengespeichert werden

  1. privater Client kann zwischenspeichern

  2. öffentlicher Client und Proxyserver können zwischenspeichern

  3. max-age=60 Der zwischengespeicherte Inhalt läuft nach 60 Sekunden ab

  4. no-cache Sie müssen den Vergleichscache verwenden, um die Daten zu überprüfen und den Quellserver dazu zu zwingen erneut überprüfen

  5. Nein – Alle Inhalte im Store werden nicht zwischengespeichert und weder erzwungenes Caching noch Vergleichs-Caching werden ausgelöst

Läuft ab: http1 .0-Inhalt, Cache-Control überschreibt ihn und teilt dem Client mit, wann der Cache abläuft.

ETag: Der Hash-Wert des Inhalts. Fügen Sie if-none-match im Anforderungsheader für die nächste Client-Anfrage hinzu: etag-Wert

Last-Modified: Der letzte Änderungszeitpunkt für die nächste Client-Anfrage. Fügen Sie if-modified-since: Last-Modified-Wert im Header hinzu

 handleCache(req, res, stats, hash) {
 // 当资源过期时, 客户端发现上一次请求资源,服务器有发送Last-Modified, 则再次请求时带上if-modified-since
 const ifModifiedSince = req.headers[&#39;if-modified-since&#39;];
 // 服务器发送了etag,客户端再次请求时用If-None-Match字段来询问是否过期
 const ifNoneMatch = req.headers[&#39;if-none-match&#39;];
 // http1.1内容 max-age=30 为强行缓存30秒 30秒内再次请求则用缓存 private 仅客户端缓存,代理服务器不可缓存
 res.setHeader(&#39;Cache-Control&#39;, &#39;private,max-age=30&#39;);
 // http1.0内容 作用与Cache-Control一致 告诉客户端什么时间,资源过期 优先级低于Cache-Control
 res.setHeader(&#39;Expires&#39;, new Date(Date.now() + 30 * 1000).toGMTString());
 // 设置ETag 根据内容生成的hash
 res.setHeader(&#39;ETag&#39;, hash);
 // 设置Last-Modified 文件最后修改时间
 const lastModified = stats.ctime.toGMTString();
 res.setHeader(&#39;Last-Modified&#39;, 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;
 }
 }
Nach dem Login kopieren

4 >

Der Client sendet Inhalte und teilt der Serverunterstützung über Accept-Encoding: gzip, deflate im Anforderungsheader mit, welche Komprimierungsformate der Server verwendet. Der Server komprimiert den Inhalt basierend auf den unterstützten Komprimierungsformaten. Wenn der Server dies nicht unterstützt, wird keine Komprimierung durchgeführt.

 getEncoding(req, res) {
  const acceptEncoding = req.headers[&#39;accept-encoding&#39;];
  // gzip和deflate压缩
  if (/\bgzip\b/.test(acceptEncoding)) {
   res.setHeader(&#39;Content-Encoding&#39;, &#39;gzip&#39;);
   return zlib.createGzip();
  } else if (/\bdeflate\b/.test(acceptEncoding)) {
   res.setHeader(&#39;Content-Encoding&#39;, &#39;deflate&#39;);
   return zlib.createDeflate();
  } else {
   return null;
  }
 }
Nach dem Login kopieren
5. Haltepunkt-Wiederaufnahme

Der Server verwendet Range: bytes=0-xxx im Anforderungsheader, um zu bestimmen, ob dieser Wert vorhanden und gültig ist Dann wird nur der angeforderte Teil des Dateiinhalts zurückgesendet, 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.

 getStream(req, res, filepath, statObj) {
  let start = 0;
  let end = statObj.size - 1;
  const range = req.headers[&#39;range&#39;];
  if (range) {
   res.setHeader(&#39;Accept-Range&#39;, &#39;bytes&#39;);
   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
  });
 }
Nach dem Login kopieren
6. Globale Befehlsausführung

implementiert über npm-Link

  1. Erstellen Sie einen Softlink für das npm-Paketverzeichnis und verknüpfen Sie ihn mit { prefix }/lib/node_modules/

  2. 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 durch die Verknüpfung von Verzeichnissen und ausführbaren Dateien global ausführbar.

Konfiguration in package.json

 {
 bin: {
 "hope-server": "bin/hope"
 }
 }
Nach dem Login kopieren
Erstellen Sie die Bin-Verzeichnis-Hope-Datei unter dem Projekt und verwenden Sie die Yargs-Konfigurationsbefehlszeile, um Parameter zu übergeben

 // 告诉电脑用node运行我的文件
 #! /usr/bin/env node
 
 const yargs = require(&#39;yargs&#39;);
 const init = require(&#39;../src/index.js&#39;);
 const argv = yargs.option(&#39;d&#39;, {
 alias: &#39;root&#39;,
 demand: &#39;false&#39;,
 type: &#39;string&#39;,
 default: process.cwd(),
 description: &#39;静态文件根目录&#39;
 }).option(&#39;o&#39;, {
 alias: &#39;host&#39;,
 demand: &#39;false&#39;,
 default: &#39;localhost&#39;,
 type: &#39;string&#39;,
 description: &#39;配置监听的主机&#39;
 }).option(&#39;p&#39;, {
 alias: &#39;port&#39;,
 demand: &#39;false&#39;,
 type: &#39;number&#39;,
 default: 8080,
 description: &#39;配置端口号&#39;
 }).option(&#39;c&#39;, {
 alias: &#39;child&#39;,
 demand: &#39;false&#39;,
 type: &#39;boolean&#39;,
 default: false,
 description: &#39;是否子进程运行&#39;
 })
 .usage(&#39;hope-server [options]&#39;)
 .example(
 &#39;hope-server -d / -p 9090 -o localhost&#39;, &#39;在本机的9090端口上监听客户端的请求&#39;
 ).help(&#39;h&#39;).argv;
 
 // 启动服务
 init(argv);
Nach dem Login kopieren
7 . Führen Sie den untergeordneten Prozess aus

Erreicht durch spawn

index.js

 const { spawn } = require(&#39;child_process&#39;);
 const Server = require(&#39;./hope&#39;);
 function init(argv) {
  // 如果配置为子进程开启服务
  if (argv.child) {
   //子进程启动服务
   const child = spawn(&#39;node&#39;, [&#39;hope.js&#39;, JSON.stringify(argv)], {
    cwd: __dirname,
    detached: true,
    stdio: &#39;inherit&#39;
   });
 
   //后台运行
   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(&#39;{&#39;)) {
 const argv = JSON.parse(process.argv[2]);
 const server = new Hope(argv);
 server.start();
 }
Nach dem Login kopieren
Quellcode und Tests

Quellcodeadresse: Hope- Server

npm install hope-server -g
Nach dem Login kopieren
Geben Sie ein beliebiges Verzeichnis ein

hope-server
Nach dem Login kopieren
Verwandte Empfehlungen:


Detaillierte Erläuterung des statischen Knotendateiservers

Verwenden Sie nodejs, einen einfachen HTTP-statischen Dateiserver, der in Python geschrieben ist

Verbesserte Version der statischen Datei server_node.js von Node.js

Das obige ist der detaillierte Inhalt vonAusführliche Erläuterung der statischen Dateiserverinstanz des Knotens. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage
Über uns Haftungsausschluss Sitemap
Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!