国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發 > JS > 正文

實戰node靜態文件服務器的示例代碼

2024-05-06 16:42:52
字體:
來源:轉載
供稿:網友

本篇文章主要介紹了實戰node靜態文件服務器的示例,分享給大家,具體如下:

支持功能:

  1. 讀取靜態文件
  2. 訪問目錄可以自動尋找下面的index.html文件, 如果沒有index.html則列出文件列表
  3. MIME類型支持
  4. 緩存支持/控制
  5. 支持gzip壓縮
  6. Range支持,斷點續傳
  7. 全局命令執行
  8. 子進程運行

1. 創建服務讀取靜態文件

首先引入http模塊,創建一個服務器,并監聽配置端口:

 const http = require('http');  const server = http.createServer();  // 監聽請求 server.on('request', request.bind(this));  server.listen(config.port, () => {  console.log(`靜態文件服務啟動成功, 訪問localhost:${config.port}`); });

寫一個fn專門處理請求, 返回靜態文件, url模塊獲取路徑:

 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); // 讀取文件,并響應 }

支持尋找index.html:

 if (pathname === '/') {  const rootPath = path.join(config.root, 'index.html');  try{   const indexStat = fs.statSync(rootPath);   if (indexStat) {    filepath = rootPath;   }  } catch(e) {     } }

訪問目錄時,列出文件目錄:

 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模板:

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

2.MIME類型支持

利用mime模塊得到文件類型,并設置編碼:

res.setHeader('Content-Type', mime.getType(filepath) + ';charset=utf-8');

3.緩存支持

http協議緩存:

Cache-Control: http1.1內容,告訴客戶端如何緩存數據,以及規則

  1. private 客戶端可以緩存
  2. public 客戶端和代理服務器都可以緩存
  3. max-age=60 緩存內容將在60秒后失效
  4. no-cache 需要使用對比緩存驗證數據,強制向源服務器再次驗證
  5. no-store 所有內容都不會緩存,強制緩存和對比緩存都不會觸發

Expires: http1.0內容,cache-control會覆蓋,告訴客戶端緩存什么時候過期

ETag: 內容的hash值 下一次客戶端請求在請求頭里添加if-none-match: etag值

Last-Modified: 最后的修改時間 下一次客戶端請求在請求頭里添加if-modified-since: Last-Modified值

 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; } }

4.壓縮

客戶端發送內容,通過請求頭里Accept-Encoding: gzip, deflate告訴服務器支持哪些壓縮格式,服務器根據支持的壓縮格式,壓縮內容。如服務器不支持,則不壓縮。

 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;  } }

5.斷點續傳

服務器通過請求頭中的Range: bytes=0-xxx來判斷是否是做Range請求,如果這個值存在而且有效,則只發回請求的那部分文件內容,響應的狀態碼變成206,表示Partial Content,并設置Content-Range。如果無效,則返回416狀態碼,表明Request Range Not Satisfiable。如果不包含Range的請求頭,則繼續通過常規的方式響應。

 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  }); }

6.全局命令執行

通過npm link實現

  1. 為npm包目錄創建軟鏈接,將其鏈到{prefix}/lib/node_modules/
  2. 為可執行文件(bin)創建軟鏈接,將其鏈到{prefix}/bin/{name}

npm link命令通過鏈接目錄和可執行文件,實現npm包命令的全局可執行。

package.json里面配置

 { bin: { "hope-server": "bin/hope" } }

在項目下面創建bin目錄 hope文件, 利用yargs配置命令行傳參數

 // 告訴電腦用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);

7.子進程運行

通過spawn實現

index.js

 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(); }

8.源碼及測試

源碼地址: hope-server

npm install hope-server -g

進入任意目錄

hope-server

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VeVb武林網。


注:相關教程知識閱讀請移步到JavaScript/Ajax教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 阿城市| 临泽县| 齐齐哈尔市| 卫辉市| 荆门市| 华容县| 福海县| 荔浦县| 揭阳市| 定襄县| 苍山县| 赤峰市| 应用必备| 健康| 安龙县| 健康| 吐鲁番市| 玛纳斯县| 疏附县| 沐川县| 筠连县| 伊金霍洛旗| 湘潭市| 玉屏| 宜州市| 台北市| 花莲县| 威宁| 井研县| 高密市| 玉树县| 清水县| 黑河市| 孟津县| 黄山市| 远安县| 漠河县| 大名县| 嘉鱼县| 奇台县| 印江|