百分百源码网-让建站变得如此简单! 登录 注册 签到领金币!

主页 | 如何升级VIP | TAG标签

当前位置: 主页>网站教程>JS教程> Node.js之静态资源效劳器实现(附代码)
分享文章到:

Node.js之静态资源效劳器实现(附代码)

发布时间:09/01 来源:未知 浏览: 关键词:
本篇文章给大家带来的内容是关于Node.js之静态资源效劳器实现(附代码),有必然的参照 价值,有需要的伴侣可以参照 一下,但愿对你有所帮忙。

本文介绍了一个简便的静态资源效劳器的实例项目,但愿能给Node.js初学者带来帮忙。项目触及到http、fs、url、path、zlib、process、child_process等模块,涵盖大量常用api;还包罗了基于http和谈的缓存战略拔取、gzip紧缩优化等;终究我们会公布到npm上,做成一个可以全局安置、使用的小工具。麻雀虽小,五脏俱全,一想是不是还有点小冲动?话不多说,放码过来。

文中源码地址在最后附录中。
可先行体验项目结果:
安置:npm i -g here11
任意文件夹地址输入命令:here

step1 创建项目

由于我们要公布到npm上,所以我们先依照国际惯例,npm init,走你!在命令行可以一路回车,有些配置会在最后的公布步骤中细说。

名目构造如下:

3011606152-5c81f592a74fd_articlex.png

bin文件夹存置我们的施行代码,web作为一个测试文件夹,里面放了些网页。

step2 码码

step2.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, parentPath) => {
    let path = parentPath = `${parentPath}/${name}`.slice(1);
    return `<p><a href="${path}">${name}</a></p>`;
}

const list = (arr, parentPath) => {
    return arr.map(name => item(name, parentPath)).join("");
}

const server = http.createServer((req, res) => {
    let _path = url.parse(req.url).pathname;//去除search
    let parentPath = _path;
    _path = path.join(__dirname, _path);
    try {
        //拿到途径所对应的文件描写对象
        let stats = fs.statSync(_path);
        if (stats.isFile()) {
            //是文件,返回文件内容
            let file = fs.readFileSync(_path);
            res.end(file);
        } else if (stats.isDirectory()) {
            //是名目,返回名目列表,让会员可以连续点击
            let dirArray = fs.readdirSync(_path);
            res.end(list(dirArray, parentPath));
        } else {
            res.end();
        }
    } catch (err) {
        res.writeHead(404, "Not Found");
        res.end();
    }
});

const port = 2234;
const hostname = "127.0.0.1";
server.listen(port, hostname, () => {
    console.log(`server is running on http://${hostname}:${port}`);
});

以上这段code就是我们的中心代码了,已经实现了中心功效,当地运转即可看到返回了文件名目,点击文件名便可阅读对应的网页、图片、文本啦。

step2.2 优化

功效实现了,但是我们可以在某些方面做做优化,晋升有用性,顺便多学习几个api(装逼技巧)。

1. stream

我们当前读取文件返回给阅读器的操纵是通过readFile一次性读出来,一次性返回,这样当然可以实现功效,但我们有更好的方式——用stream(流)停止IO操纵。stream并不是node.js独占的概念,而是操纵系统最根本的一种操纵情势,所以理论上讲,任何一门server端说话都实现了stream的API。

为什么讲用stream是一种更好的方式?由于一次性读取、操纵大文件,内存和网络是吃不消的,特别在会员拜访量比力大的状况下更为明显;而借助stream可以让数据活动起来,一点一点操纵,从而晋升机能。代码修改如下:

if (stats.isFile()) {
    //是文件,返回文件内容
    //在createServer时传入的回调函数被增加到了"request"事件上,回调函数的两个形参req和res
    //离别为http.IncomingMessage对象和http.ServerResponse对象
    //并且它们都实现了流接口
    let readStream = fs.createReadStream(_path);
    readStream.pipe(res);
}

编码实现非常简便,在需要返回文件内容时,我们创立了一个可读流,并把它直接导向了res对象。

2. gzip紧缩

gzip紧缩带来的机能(会员拜访体验)晋升是非常明显的,特别在当下spa利用大行其道的时代,开启gzip紧缩,可以大幅减小js、css等文件资源的体积,晋升会员拜访速度。作为一个静态资源效劳器,我们当然要加上这个功效。

node中有一个zlib的模块,供给了许多紧缩相关的api,我们就用它来实现:

const zlib = require("zlib");

if (stats.isFile()) {
    //是文件,返回文件内容

    res.setHeader("content-encoding", "gzip");
    
    const gzip = zlib.createGzip();
    let readStream = fs.createReadStream(_path);
    readStream.pipe(gzip).pipe(res);
}

有了stream的使用经历,我们再看这段代码的时候就好懂得多了。把文件流先导向gzip对象,再导向res对象。此外,使用gzip紧缩的时候还需要留意一点:需要把响应头里的content-encoding设定为gzip。不然阅读器会把一堆乱码展现出来。

3. http缓存

缓存这个东西让人又爱又恨,用得好,可以晋升会员体验,减轻效劳器压力;用得不好,大概就会面临许许多多奇惊奇怪的问题。一样来讲阅读器http缓存分为强缓存(非验证性缓存)和协商缓存(验证性缓存)。

什么叫强缓存呢?强缓存是由cache-control和expires两个首部字段操纵的,此刻一样用cache-control。比方我们设定了cache-control: max-age=31536000的响应头,就是告诉阅读器这个资源有一年的缓存期,一年内不消向效劳端发送恳求,直接从缓存中读取资源。

而协商性缓存是使用if-modified-since/last-modified、if-none-match/etag等首部字段,配合强缓存,在强缓存没有命中(或告知阅读器no-cache)的时候,向效劳器发送恳求,确定资源的有效性,决议从缓存中读取或是返回新的资源。

有了以上概念,我们便可以拟定我们的缓存战略:

if (stats.isFile()) {
    //是文件,返回文件内容
    
    //增添推断文件可否有改动,没有改动返回304的逻辑
    
    //从恳求头猎取modified时间
    let IfModifiedSince = req.headers["if-modified-since"];
    //猎取文件的修改日期——时间戳格局
    let mtime = stats.mtime;
    //假如效劳器上的文件修改时间小于等于恳求头携带的修改时间,则认定文件没有转变
    if (IfModifiedSince && mtime <= new Date(IfModifiedSince).getTime()) {
        //返回304
        res.writeHead(304, "not modify");
        return res.end();
    }
    //第一次恳求或文件被修改后,返回给客户端新的修改时间
    res.setHeader("last-modified", new Date(mtime).toString());
    res.setHeader("content-encoding", "gzip");
    let reg = /\.html$/;
    //不一样的文件类型设定不一样的cache-control
    if (reg.test(_path)) {
        //我们对html文件施行每次必需向效劳器验证资源有效性的战略
        res.setHeader("cache-control", "no-cache");
    } else {
        //我们对其余的静态资源文件采取强缓存战略,一个月内无需向效劳器索取
        res.setHeader("cache-control", `max-age=${1 * 60 * 60 * 24 * 30}`);
    }
    
    //施行gzip紧缩
    const gzip = zlib.createGzip();
    let readStream = fs.createReadStream(_path);
    readStream.pipe(gzip).pipe(res);
}

这样一套缓存战略在现代前端项目体系下还是比力适宜的,特别是关于spa利用来讲。我们但愿index.html能够包管每次向效劳器验证可否有更新,而其余的文件统一当地缓存一个月(本人定);通过webpack打包或其他工程化方式构建之后,js、css内容假如发生转变,文件名响应更新,index.html插入的manifest(或script链接、link链接等)清单会更新,包管会员能够实时得到最新的资源。

当然,缓存之路千万条,适合业务才重要,大家可以灵敏拟定。

4. 命令行参数

作为一个在命令行施行的工具,如何能不象征性的支撑几个参数呢?

const config = {
    //从命令行中猎取端标语,假如未设定采纳默许
    port: process.argv[2] || 2234,
    hostname: "127.0.0.1"
}
server.listen(config.port, config.hostname, () => {
    console.log(`server is running on http://${config.hostname}:${config.port}`);
});

这里就简便的举个栗子啦,大家可以自在发挥!

5. 主动翻开阅读器

虽然没太大卵用,但还是要加。我就是要让你们知道,我加完之后什么样,你们就是啥样 :-( duang~

const exec = require("child_process").exec;
server.listen(config.port, config.hostname, () => {
    console.log(`server is running on http://${config.hostname}:${config.port}`);
    exec(`open http://${config.hostname}:${config.port}`);
});

6. process.cwd()

用process.cwd()代替__dirname。
我们终究要做成一个全局并且可以在任意名目下调取的命令,所以拼接path的代码修改如下:

//__dirname是当前文件的名目地址,process.cwd()返回的是足本施行的途径
_path = path.join(process.cwd(), _path);

step3 公布

根本上我们的代码都写完了,可以思考公布了!(不公布到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/gww666/here.git"
    },
    "scripts": {
        "test": "node bin/index.js"
    },
    "keywords": [
        "node"
    ],
    "author": "gw666",
    "license": "ISC"
}

其中bin和private较为重要,其余的依照本人的项目状况填写。
bin这个配置代表的是npm i -g xxx之后,我们运转here命令所施行的文件,“here”这个名字可以随便起。

step3.2 声明足本施行类型

在index.js文件的开头加上:#!/usr/bin/env node
不然linux上运转会报错。

step3.3 注册npm账号

牵强贴一手命令,还不分明自行baidu:

没有账号的先增加一个,施行:
npm adduser

然后顺次填入
Username: your name
Password: your password
Email: yourmail

npm会给你发一封验证邮件,记得点一下,不然会公布失败。

施行登录命令:
npm login

施行公布命令:
npm publish

公布的时候记得把项目名字、版本号、作者、仓库啥的改一下,别填成我的。
还有readme文件写一下,好歹告诉别人咋用,根本上和文首所说的用途是一样的。

好了,齐活。

step3.4

还等啥啊,赶紧把npm i -g xxx 这行命令发给你的小伙伴啊。什么?你没有小伙伴?告辞!

本文项目源码地址:https://github.com/gww666/here

以上就是Node.js之静态资源效劳器实现(附代码)的具体内容,更多请关注百分百源码网其它相关文章!

打赏

打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

百分百源码网 建议打赏1~10元,土豪随意,感谢您的阅读!

共有151人阅读,期待你的评论!发表评论
昵称: 网址: 验证码: 点击我更换图片
最新评论

本文标签

广告赞助

能出一分力是一分吧!

订阅获得更多模板

本文标签

广告赞助

订阅获得更多模板