手机版

Node.js手动创建静态资源服务器的方法

时间:2021-08-27 来源:互联网 编辑:宝哥软件园 浏览:

简介

介绍一个简单的静态资源服务器的示例项目,希望能给Node.js初学者带来帮助该项目涉及http、fs、url、path、zlib、process、child_process等模块,涵盖了大量常用的api;还包括基于http协议的缓存策略选择、gzip压缩优化等,最后我们会发布到npm,让它成为一个可以全球安装使用的小工具。麻雀虽小而全,不知是否还有点兴奋。没什么好说的,把它写在代码上。

源代码地址在最后的附录中。

先体验项目效果:

安装:npm i -g此处11

在此输入任何文件夹地址的命令

创建新项目

因为我们要发布给npm,所以要遵循国际惯例,npm init,走!您可以在命令行上一直按enter键,一些配置将在最后的发布步骤中详细介绍。

目录结构如下:

Bin文件夹存储我们的执行代码,web作为一个测试文件夹,其中放置了一些网页。

第二步代码

步骤2.1原型

静态资源服务器,一般来说就是我们在浏览器的地址栏中以“http://域名/test/index.html”的形式输入一个地址。服务器从根目录下的相应文件夹中找到index.html,读出文件内容并将其返回给浏览器,浏览器将它呈现给用户。

const http=require(' http ');const URL=require(' URL ');const fs=require(' fs ');const path=require(' path ');const item=(name,parent path)={ let path=parent path=` $ { parent path }/$ { name } ` . slice(1);返回` diva href=' $ { path } ' rel=' external no follow ' $ { name }/a/div `;}const list=(arr,parentPath)={ return arr . map(name=item(name,parent path))。join(' ');} const server=http . CreateServer((req,RES)={ let _ path=URL . parse(req . URL)。路径名;//移除搜索让parentPath=_ path_path=path.join(__dirname,_ path);尝试{//获取路径对应的文件描述对象let stats=fs . statsync(_ path);如果(stats.isFile()) {//是文件,返回文件内容let file=fs . readfilesync(_ path);res.end(文件);} else if (stats。isdirectory()){//是一个目录,它返回目录列表,这样用户可以继续点击let dir array=fs。readdir sync(_ path);res.end(list(dirArray,parentPath));} else { RES . end();} } catch (err) { res.writeHead(404,'未找到');RES . end();}});const port=2234const主机名=' 127 . 0 . 0 . 1 ';server.listen(端口,主机名,()={ console.log(`server运行在http://${hostname}:${port} `)上);});以上代码是我们的核心代码,核心功能已经实现。可以看到本地运行时会返回文件目录,点击文件名可以浏览对应的网页、图片和文字。

步骤2.2优化

功能已经实现,但我们可以在某些方面进行优化,提高实用性,顺便学习更多的api(假装技巧)。

1.溪流

目前我们读取文件返回浏览器的操作是通过readFile读取一次,返回一次,当然可以实现功能,但是用stream ——做IO操作,我们有更好的方法。Stream不是node.js独有的概念,而是操作系统的一种基本操作形式,所以理论上任何服务器端语言都实现了stream的API。

为什么stream是更好的方法?因为一次读取和操作大文件,内存和网络难以承受,尤其是用户访问量大的情况下;借助流,数据流可以一点一点地移动和操作,从而提高性能。按如下方式修改代码:

如果(stats.isFile()) {//是文件,则返回文件的内容。//创建createServer时传入的回调函数已添加到“请求”事件中。回调函数的两个参数req和res //是http。IncomingMessage对象和http。ServerResponse对象//,并且它们都实现了让readstream=fs的流接口。create readstream(_ path);readstream . pipe(RES);}编码实现非常简单。当我们需要返回文件内容时,我们创建一个可读的流,并将其指向res对象。

2.gzip压缩

gzip压缩带来的性能(用户访问体验)非常明显,尤其是在当前spa应用盛行的时代,开启gzip压缩可以大大减少js、css等文件资源的体积,提高用户访问速度。作为一个静态资源服务器,我们当然要加入这个功能。

node中有一个zlib模块,提供了很多压缩相关的API,所以我们用它来实现:

const zlib=require(' zlib ');如果(stats.isFile()) {//是文件,返回文件内容RES . setheader(' content-encoding ',' gzip ');const gzip=zlib . creategzip();让readStream=fs . createreadstream(_ path);readStream.pipe(gzip)。管道(RES);}有了使用stream的经验,当我们再次查看这段代码时,会更容易理解。文件流首先指向gzip对象,然后指向res对象。此外,当使用gzip压缩时,应该注意响应头中的内容编码应该设置为gzip。否则,浏览器将显示一堆乱码字符。

3.http缓存

缓存这个东西让人又爱又恨,可以提升用户体验,减轻服务器压力;如果你没有很好地使用它,你可能会面临各种奇怪的问题。一般来说,浏览器http缓存分为强缓存(非认证缓存)和协商缓存(认证缓存)。

什么是强缓存?强缓存由两个头字段控制,缓存控制和过期。现在通常使用缓存控制。比如我们设置了cache-control : max-age=31536000的响应头,告诉浏览器这个资源有一年的缓存期,一年内不需要向服务器发送请求,直接从缓存中读取资源。

协商缓存使用报头字段,如if-modified-自/上次修改,if-none-match/etag等。当强缓存未命中(或告知浏览器无缓存)时,它会向服务器发送请求,以确认资源的有效性,并决定是否从缓存中读取或返回新资源。

有了以上概念,我们可以制定我们的缓存策略:

如果(stats.isFile()) {//是文件,则返回文件的内容//添加判断文件是否被更改的逻辑,不更改逻辑返回304//从请求头获取修改时间。让if修改start=req。标题[' if-modified-after '];//获取文件的修改日期——时间戳格式让mtime=stats.mtime//如果服务器上的文件修改时间小于或等于请求头携带的修改时间,则假设文件在(ifmodifiedsentime=new date(ifmodifiedsafter))没有发生变化。gettime()){//返回304个字符。writehead (304,“未修改”);return RES . end();}//在第一个请求或文件被修改后,返回新的修改时间res.setheader('上次修改',新的日期(mtime)。tostring())发送给客户端;res.setHeader('内容编码',' gzip ');让reg=/\。html $/;//不同的文件类型设置不同的缓存控制if (reg。test(_ path)){//我们执行策略Res. Setheader ('cache-control ',' no-cache '),对于html文件,每次必须向服务器验证资源有效性;} else {//其余静态资源文件我们采用强缓存策略,一个月内不需要向服务器请求res.setheader ('cache-control ',` max-age=$ { 1 * 60 * 60 * 24 * 30 } `);}//执行gzip压缩const gzip=zlib . creategzip();让readStream=fs . createreadstream(_ path);readStream.pipe(gzip)。管道(RES);}这样的缓存策略在现代前端项目体系下是相当适合的,尤其是对于spa应用。我们希望index.html能保证每次验证服务器是否有更新,剩下的文件都会在本地缓存一个月(自行决定);如果js和css的内容发生变化,文件名会相应更新,清单(或脚本链接、链接链接等)也会相应更新。)index.html插入的列表将被更新,以确保用户可以实时获得最新的资源。

当然缓存的方式有上千种,所以适合业务很重要,大家可以灵活制作。

4.命令行参数

作为一个在命令行上执行的工具,怎么能不象征性地支持几个参数呢?

Const config={//从命令行获取端口号。如果未设置,请使用默认端口:process.argv [2] | | 2234,主机名3360 ' 127 . 0 . 0 . 1 ' } server . listen(config . port,config.hostname,()={ console.log(`server运行于http://$ { config . hostname } : $ { config . port } `);});这里有一个栗子的简单例子。大家可以自由发挥!

5.自动打开浏览器

虽然鸡蛋用的不多,但还是要加。我只是想在加完之后让你知道你是什么样子的。-(duang~

const exec=require(' child _ process ')。执行董事;server.listen(config.port,config.hostname,()={ console.log(`server运行在http://$ { config . hostname } : $ { config . port } `)上);exec(` open http://$ { config . hostname } : $ { config . port } `);});6.process.cwd()

请使用process.cwd()而不是__dirname。

我们最终将生成一个可以在任何目录中调用的全局命令,因此拼接路径的代码修改如下:

//__dirname是当前文件的目录地址,process.cwd()返回脚本执行的路径_ path=path.join (process.cwd(),_ path);释放

基本上我们的代码已经写好了,可以考虑发布了!(为什么不在npm上显示?)

step3.1 package.json

获取一个json文件,其配置类似于以下内容:

{ 'name': 'here11 ',' version': '0.0.13 ',' private': false,' description ' : ' a node static assets server ',' bin': { 'here': '。/bin/index.js' },' repository ' : { ' type ' : ' git ',' URL ' : ' https://github.com/gww 666/here . git ' },Scripts ' : { ' test ' : ' node bin/index . js ' },'关键字' : ['node'],' author' :' gw666 ',' license' :' isc

bin的配置代表我们在npm i -g xxx后运行here命令时执行的文件,名称“here”可以随意命名。

步骤3.2声明脚本执行类型

在index.js文件的开头添加#号!/usr/bin/env节点

否则,在linux上运行会报告错误。

步骤3.3注册国家预防机制账户

勉强贴了一条命令,百度不清楚:

如果没有账号,先加一个,执行:

Npm添加用户,然后填写

用户名:您的姓名密码:您的密码邮件:您的邮件

Npm会给你发一封验证邮件,记得点击,否则会发布失败。

执行登录命令:

通过npm登录执行释放命令:

npm publish发布的时候记得更改项目名称、版本号、作者、仓库等等,不要填成我的。还有一个自述文件要写,至少告诉别人怎么用,和开头提到的用法基本一致。

好吧,让我们住在一起。

步骤3.4

你还在等什么?快速发送npm i -g xxx命令给你的朋友。什么事?你没有朋友吗?再会!

以上就是本文的全部内容。希望对大家的学习有帮助,支持我们。

版权声明:Node.js手动创建静态资源服务器的方法是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。