首页 web前端 js教程 node静态文件服务器实例详解

node静态文件服务器实例详解

Mar 12, 2018 am 09:35 AM
node 实例 服务器

本文主要和大家介绍了实战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(&#39;Content-Type&#39;, mime.getType(filepath) + &#39;;charset=utf-8&#39;);
登录后复制

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[&#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;
 }
 }
登录后复制

4.压缩

客户端发送内容,通过请求头里Accept-Encoding: gzip, deflate告诉服务器支持哪些压缩格式,服务器根据支持的压缩格式,压缩内容。如服务器不支持,则不压缩。

 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;
  }
 }
登录后复制

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[&#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
  });
 }
登录后复制

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(&#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);
登录后复制

7.子进程运行

通过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();
 }
登录后复制

8.源码及测试

源码地址: hope-server

npm install hope-server -g
登录后复制

进入任意目录

hope-server
登录后复制

相关推荐:

node静态文件服务器详解

使用nodejs、Python写的一个简易HTTP静态文件服务器

Node.js静态文件服务器改进版_node.js

以上是node静态文件服务器实例详解的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
3 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

电驴搜索连不上服务器如何解决 电驴搜索连不上服务器如何解决 Jan 25, 2024 pm 02:45 PM

解决办法:1、检查电驴设置,确保已输入正确的服务器地址和端口号;2、检查网络连接,确保计算机已连接到互联网,并重置路由器;3、检查服务器是否在线,如果您的设置和网络连接都没有问题,则需要检查服务器是否在线;4、更新电驴版本,访问电驴官方网站,下载最新版本的电驴软件;5、寻求帮助。

无法连接到RPC服务器导致无法进入桌面的解决方法 无法连接到RPC服务器导致无法进入桌面的解决方法 Feb 18, 2024 am 10:34 AM

RPC服务器不可用进不了桌面怎么办近年来,计算机和互联网已经深入到我们的生活中的各个角落。作为一种集中计算和资源共享的技术,远程过程调用(RPC)在网络通信中起着至关重要的作用。然而,有时我们可能会遇到RPC服务器不可用的情况,导致无法进入桌面。本文将介绍一些可能导致此问题的原因,并提供解决方案。首先,我们需要了解RPC服务器不可用的原因。RPC服务器是一种

CentOS安装fuse及CentOS安装服务器详解 CentOS安装fuse及CentOS安装服务器详解 Feb 13, 2024 pm 08:40 PM

作为一名LINUX用户,我们经常需要在CentOS上安装各种软件和服务器,本文将详细介绍如何在CentOS上安装fuse和搭建服务器的过程,帮助您顺利完成相关操作。CentOS安装fuseFuse是一个用户空间文件系统框架,允许非特权用户通过自定义文件系统实现对文件系统的访问和操作,在CentOS上安装fuse非常简单,只需按照以下步骤操作:1.打开终端,以root用户登录。2.使用以下命令安装fuse软件包:```yuminstallfuse3.确认安装过程中的提示,输入`y`继续。4.安装完

如何将Dnsmasq配置为DHCP中继服务器 如何将Dnsmasq配置为DHCP中继服务器 Mar 21, 2024 am 08:50 AM

DHCP中继的作用是将接收到的DHCP数据包转发到网络上的另一个DHCP服务器,即使这两个服务器位于不同的子网中。通过使用DHCP中继,您可以实现在网络中心部署一个集中式的DHCP服务器,并利用它为所有网络子网/VLAN动态分配IP地址。Dnsmasq是一种常用的DNS和DHCP协议服务器,可以配置为DHCP中继服务器,以帮助管理网络中的动态主机配置。在本文中,我们将向您展示如何将dnsmasq配置为DHCP中继服务器。内容主题:网络拓扑在DHCP中继上配置静态IP地址集中式DHCP服务器上的D

用PHP构建IP代理服务器的最佳实践指南 用PHP构建IP代理服务器的最佳实践指南 Mar 11, 2024 am 08:36 AM

在网络数据传输中,IP代理服务器扮演着重要的角色,能够帮助用户隐藏真实IP地址,保护隐私、提升访问速度等。在本篇文章中,将介绍如何用PHP构建IP代理服务器的最佳实践指南,并提供具体的代码示例。什么是IP代理服务器?IP代理服务器是一种位于用户与目标服务器之间的中间服务器,它充当用户与目标服务器之间的中转站,将用户的请求和响应进行转发。通过使用IP代理服务器

epic服务器离线进不了游戏怎么办?epic离线进不了游戏解决方法 epic服务器离线进不了游戏怎么办?epic离线进不了游戏解决方法 Mar 13, 2024 pm 04:40 PM

  epic服务器离线进不了游戏怎么办?这个问题想必很多小伙伴都有遇到过,出现了此提示就是导致正版的游戏无法启动,那么出现这个问题一般是网络和安全软件干扰导致的,那么应该怎么解决呢,本期小编就来和大伙分享解决方法,希望今日的软件教程可以帮助各位解决问题。  epic服务器离线进不了游戏怎么办:  1、很可能是被安全软件干扰了,将游戏平台和安全软件关闭在重启。  2、其次就是网络波动过大,尝试重启一次路由器,看看是否有效,如果条件可以的话,可以尝试使用5g移动网络来进行操作。  3、然后有可能是更

Pi Node教学:什么是Pi节点?如何安装和设定Pi Node? Pi Node教学:什么是Pi节点?如何安装和设定Pi Node? Mar 05, 2025 pm 05:57 PM

PiNetwork节点详解及安装指南本文将详细介绍PiNetwork生态系统中的关键角色——Pi节点,并提供安装和配置的完整步骤。Pi节点在PiNetwork区块链测试网推出后,成为众多先锋积极参与测试的重要环节,为即将到来的主网发布做准备。如果您还不了解PiNetwork,请参考Pi币是什么?上市价格多少?Pi用途、挖矿及安全性分析。什么是PiNetwork?PiNetwork项目始于2019年,拥有其专属加密货币Pi币。该项目旨在创建一个人人可参与

如何在服务器上安装 PHP FFmpeg 扩展? 如何在服务器上安装 PHP FFmpeg 扩展? Mar 28, 2024 pm 02:39 PM

如何在服务器上安装PHPFFmpeg扩展?在服务器上安装PHPFFmpeg扩展可以帮助我们在PHP项目中处理音视频文件,实现音视频文件的编解码、剪辑、处理等功能。本文将介绍如何在服务器上安装PHPFFmpeg扩展,以及具体的代码示例。首先,我们需要确保服务器上已经安装了PHP以及FFmpeg。如果没有安装FFmpeg,可以按照以下步骤安装FFmpe

See all articles