用node http模塊搭建服務器一直被用做項目實踐及開發,深刻學習後,對node搭建http服務器有了新的瞭解和認識,寫此文總結羅列一下node
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
curl -v -H "Accept-Encoding:deflate" http://localhost:8080/msg.txt
windows
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();
}
}
複製代碼
fs.createReadStream(filepath).pipe(zlib.xxx()).pipe(res);
複製代碼
let { promisify } = require('util');
let stat = promisify(fs.stat);
複製代碼
緩存能夠減小對服務器的請求,加快請求效率數組
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);
}
}
});
複製代碼
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);
}
}
});
複製代碼
res.setHeader('Expires', expires.toUTCString());
res.setHeader('Cache-Control', 'max-age=60');
複製代碼
$ touch hello.shpromise
$ chmod +x hello.sh瀏覽器
$ ./hello.sh緩存
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);
複製代碼
{
"name": "hello",
"bin": {
"hello": "hello"
}
}
複製代碼
執行 npm link 命令。
$ npm link
複製代碼
就能夠直接執行 hello命令了