手机版

用一行代码实现静态文件服务器的方法和步骤

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

静态文件服务器的实现

Nodejs不仅可以用来写服务器接口,还可以代替nginx作为静态文件服务器,几分钟就可以完成。话不多说,先码:

var server=http . createserver(function(req,RES){ fs . createreadstream(path . resolve(_ _ dirname,'.'req.url))。管道(RES);})在项目的根目录下创建一个hello.html文件来测试hello.html的内容,如下所示:

H1hello,world/h1node app.js运行,打开浏览器访问:http://localhost/hello.html

回头看看代码,真的就这么简单,感谢节点Stream类强大的管道方法。fs.createReadStream读取本地文件创建一个可读的fs.createReadStream类的一个实例),然后使用管道将其引导到res响应流,这是http的一个实例。服务器响应类和从流类继承的可写流。

http的继承关系。服务器响应类如下:

安全考虑

上面的代码实现了一个静态文件服务器后,意味着项目根目录下的所有文件(递归)都可以通过浏览器直接访问下载,会带来一些安全问题。想想看,你的服务器端代码和配置文件可以通过浏览器直接下载,所以需要在代码中加入一些限制,比如只能访问特定目录下的文件和特定扩展名的文件,这是不够的。参考OWasp十大安全风险(第4条-不安全对象的直接引用),攻击者仍然可以通过以下方式访问其他目录././目录回溯,以及所有包含.应该被过滤掉。

实现矿井类型

mime类型是指http响应头中的内容类型字段,它决定了浏览器如何解析文件,是直接显示为纯文件(text/plain)、呈现为html文件(text/html),还是下载为二进制文件,无法输出正确的矿类型,可能会导致图片文件无法显示、字体文件无效、视频文件无法播放等问题。实现起来也很简单,只需要制作一个不同文件扩展名的映射表,在响应头的内容类型字段中输出对应的矿类型即可。

完整的代码如下:

const http=require(' http ');const Path=require(' Path ');const fs=require(' fs ');var server=http . createserver(function(req,RES){ const fileName=path . resolve(_ _ dirname,'.'req . URL);const extName=Path.extname(文件名)。substr(1);If (fs.existsSync(fileName)) {//判断本地文件是否有varmine type map={ html 3360 ' text/html;charset=utf-8 ',htm : ' text/html;charset=utf-8 ',XML : ' text/XML;charset=utf-8 ',png:'image/png ',jpg:'image/jpeg ',jpeg:'image/jpeg ',gif:'image/gif ',CSS : ' text/CSS;charset=utf-8 ',txt : ' text/plain;charset=utf-8 ',mp3:'audio/mpeg ',mp4:'video/mp4 ',ico:'image/x-icon ',tif:'image/tiff ',svg:'image/svg xml ',zip:'application/zip ',ttf:'font/ttf ',woff:'font/woff ',woff2:'font/woff2 ',} if(if} var stream=fs . CreateReadStream(FIlename);蒸汽管道;} })server . listen(80);实现gzip

对于html、js、css等文本类型的文件,采用gzip压缩可以大大减少传输量,提高服务器传输性能。当然,这会消耗服务器的一点cpu性能。如果客户端浏览器支持gzip压缩,请求头的accept-encoding中会携带gzip关键字,gzip压缩可以使用node自带的zlib类来实现。只要再向stream.pip添加一层,它就会首先转移到gzip流,然后导出到res stream。当然,还需要在响应头中加入Content-Encoding作为gzip,这样浏览器才能正确识别出http正文被gzip算法压缩并自动解压缩。

代码如下:

const zlib=require(' zlib ');if(req . headers[' accept-encoding '])。indexOf(' gzip ')=0(extName==' js ' | | extName==' CSS ' | | extName==' html ')){ RES . setheader(' Content-Encoding ',' gzip ');const gzip=zlib . creategzip();stream.pipe(gzip)。管道(RES);}客户端缓存

http协议的缓存协商过程相对较长,在响应头中会生成两个参数,expire(绝对时间)和cache-control(相对时间)。当浏览器下次请求文件时,分为以下几种情况:

如果未达到到期时间,浏览器将不会请求文件直接读取缓存。如果到达到期时间,文件的最后修改日期将被携带在请求头的最后修改字段中。如果比较时间戳与服务器文件一致,HTTP返回304:未修改。如果按下f5刷新,缓存的到期时间将记录在请求头的“如果修改-自”字段中。如果比较时间戳与服务器文件一致,HTTP将返回304: Not Modified ctrl f5刷新,请求头将携带cache-control: no-cache,强制禁用缓存。重新下载文件有很多逻辑分支,但都是日期比较。写出来缓存协商过程比较容易,感兴趣的同学可以自己实现

高性能静态文件服务器的优化

如果想做一个高性能的静态文件服务器,仅仅实现gzip和缓存协商是不够的,这涉及到本地文件的频繁读取,高并发下I/O会成为瓶颈。考虑到服务器上的文件很少更新,可以用Buffer将文件流缓存到内存中,请求时先在内存中查找匹配项。如果命中,直接从内存返回,避免读取磁盘,gzip也不需要压缩。当然如果文件太多,内存会飙升,所以需要考虑淘汰算法,只缓存访问次数高的文件,淘汰访问次数低的文件。

使用fs.watch监控目录文件的更改,如果文件更新,则删除缓存。

摘要

Node.js内置的pipe方法可以轻松将服务器本地文件输出到http响应流,gzip压缩也可以通过pipe实现。通过与输出矿类型匹配实现的静态服务器可以满足一般的业务需求。想要实现一个高性能的静态文件服务器,还需要实现客户端缓存和服务器端缓存的功能(本文提供思路,跟着地图走也不难)。

最后,推荐一个个人开源项目node.js web开发框架,它已经包含了静态文件服务器WebContext : https://github.com/windyfancy/webcontext的功能

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

版权声明:用一行代码实现静态文件服务器的方法和步骤是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。