Node.js 靜態服務器新知

用node http模塊搭建服務器一直被用做項目實踐及開發,深刻學習後,對node搭建http服務器有了新的瞭解和認識,寫此文總結羅列一下node

  • 支持gzip壓縮
  • 緩存支持/控制
  • yargs與自動化

Gzip

GZIP最先由Jean-loup Gailly和Mark Adler建立,用於UNIX系統的文件壓縮。咱們在Linux中常常會用到後綴爲.gz的文件,它們就是GZIP格式的。現今已經成爲Internet 上使用很是廣泛的一種數據壓縮格式,或者說一種文件格式。HTTP協議上的GZIP編碼是一種用來改進WEB應用程序性能的技術。大流量的WEB站點經常使用GZIP壓縮技術來讓用戶感覺更快的速度。這通常是指WWW服務器中安裝的一個功能,當有人來訪問這個服務器中的網站時,服務器中的這個功能就將網頁內容壓縮後傳輸到來訪的電腦瀏覽器中顯示出來.通常對純文本內容可壓縮到原大小的40%.這樣傳輸就快了,效果就是你點擊網址後會很快的顯示出來.固然這也會增長服務器的負載. 通常服務器中都安裝有這個功能模塊的.算法

HTTP 請求頭 Accept-Encoding 會將客戶端可以理解的內容編碼方式——一般是某種壓縮算法——進行通知。經過內容協商的方式,服務端會選擇一個客戶端提議的方式,使用並在響應報文首部 Content-Encoding 中通知客戶端該選擇。shell

Accept-Encoding:gzip, deflate, br//當前請求支持格式爲gzip,defalte,brnpm

Content-Encoding:gzip // 當前內容壓縮格式爲gzipjson

能夠用命令行設置請求 Accept-Encoding頭

curl -v -H "Accept-Encoding:deflate" http://localhost:8080/msg.txtwindows

http與Gzip

function request(req, res) {
    let { pathname } = url.parse(req.url);// /msg.txt
    //D:\vipcode\201801\16.http\msg.txt
    let filepath = path.join(__dirname, pathname);
    try {
        // await is only valid in async function
        let statObj = await stat(filepath);
        //能夠根據不一樣的文件內容類型返回不一樣的Content-Type
        res.setHeader('Content-Type', mime.getType(pathname));
        //爲了兼容不一樣的瀏覽器,node把全部的請求頭全轉成了小寫
        let acceptEncoding = req.headers['accept-encoding'];
        // 內容協商
        if (acceptEncoding) {
            if (acceptEncoding.match(/\bgzip\b/)) {
                //服務器告訴 客戶端我用什麼壓縮方法壓縮了
                res.setHeader('Content-Encoding', 'gzip');
                fs.createReadStream(filepath).pipe(zlib.createGzip()).pipe(res);
            } else if (acceptEncoding.match(/\bdeflate\b/)) {
                res.setHeader('Content-Encoding', 'deflate');
                fs.createReadStream(filepath).pipe(zlib.createDeflate()).pipe(res);
            } else {
                fs.createReadStream(filepath).pipe(res);
            }
        } else {
            fs.createReadStream(filepath).pipe(res);
        }
    } catch (e) {
        res.statusCode = 404;
        res.end();
    }
}
複製代碼

根據拿到的 req.headers['accept-encoding'];類型對請求的靜態資源進行相同類型的壓縮

fs.createReadStream(filepath).pipe(zlib.xxx()).pipe(res);
複製代碼
tip:能夠用util模塊中的promisify 將一個異步方法轉出一個返回promise的方法 (node v8以上)
let { promisify } = require('util'); 
let stat = promisify(fs.stat);
複製代碼

cache

緩存能夠減小對服務器的請求,加快請求效率數組

  • lastModify
  • etag
  • expires
lastModify 經過最後修改時間來判斷緩存是否可用
fs.stat(filepath, (err, stat) => {
        if (err) {
            return sendError(req, res);
        } else {
            let ifModifiedSince = req.headers['if-modified-since'];//請求頭資源上次修改時間
            let LastModified = stat.ctime.toGMTString();//文件上次修改時間
            if (ifModifiedSince == LastModified) {// 若是相等則返回304
                res.writeHead(304);
                res.end('');
            } else {
                return send(req, res, filepath, stat);
            }
        }
    });
複製代碼
ETag是實體標籤的縮寫,根據實體內容生成的一段hash字符串,能夠標識資源的狀態。當資源發生改變時,ETag也隨之發生變化。 ETag是Web服務端產生的,而後發給瀏覽器客戶端。
fs.stat(file, (err, stat) => {
        if (err) {
            sendError(err, req, res, file, stat);
        } else {
            let ifNoneMatch = req.headers['if-none-match'];
            let etag = crypto.createHash('sha1').update(stat.ctime.toGMTString() + stat.size).digest('hex');
            if (ifNoneMatch) {
                if (ifNoneMatch == etag) {
                    res.writeHead(304);
                    res.end();
                } else {
                    send(req, res, file, etag);
                }
            } else {
                send(req, res, file, etag);
            }
        }
    });
複製代碼
設置服務器響應消息頭字段Expires
res.setHeader('Expires', expires.toUTCString());
res.setHeader('Cache-Control', 'max-age=60');
複製代碼

自動化

mac新建自動化shell腳本區別與windows

$ touch hello.shpromise

$ chmod +x hello.sh瀏覽器

$ ./hello.sh緩存

安裝yargs

yargs 模塊可以解決如何處理命令行參數。它也須要安裝。
npm i yargs --save
複製代碼

編輯hello.sh

let yargs = require('yargs');
//它能夠幫咱們解析命令行參數,把參數數組變成對象的形式
// -n  --name
let argv = yargs.options('n', {
    alias: 'name',//別名
    demand: true,//必填
    default: 'yuanyuan',
    description: '請輸入你的姓名'
})
    .usage('hellp [opitons]')
    .help()//指定幫助信息
    .example('hello -name yuanyuan', '執行hello命令,而後傳入name參數爲yuanyuan')
    .alias('h', 'help')
    .argv;
console.log(argv);

console.log('hello ' + argv.name);
複製代碼

添加package.json,並添加如下內容

{
  "name": "hello",
  "bin": {
    "hello": "hello"
  }
}
複製代碼

執行 npm link 命令。

$ npm link
複製代碼

就能夠直接執行 hello命令了

相關文章
相關標籤/搜索