nodeJS靜態(tài)服務(wù)器

引入依賴模塊

let config = require('./config');
let chalk = require('chalk');//粉筆模塊(命令行變色)
let http = require('http');//http模塊
let fs = require('fs');//文件模塊
let zlib = require('zlib');
let handlebars = require('handlebars');//模板引擎
let url = require('url');//url模塊解析請(qǐng)求url
let mime = require('mime');//mime模塊通過(guò)文件名稱/路徑拿到內(nèi)容類型
let path = require('path');
let {promisify,inspect} = require('util');
let stat = promisify(fs.stat);
let readdir = promisify(fs.readdir);
process.env.DEBUG = 'static:*';
let debug = require('debug')('static:app');

編譯模板函數(shù)

function list() {
    //編譯模板,得到渲染方法,傳入數(shù)據(jù)
    let tmpl = fs.readFileSync(path.resolve(__dirname,'src/template','list.html'),'utf8');
    return handlebars.compile(tmpl);//返回一個(gè)函數(shù)
}

此函數(shù)主要用于編譯模板,返回一個(gè)文件list列表用于返回給客戶端。

start方法啟動(dòng)服務(wù)

start(){
    //啟動(dòng)服務(wù)
    let server = http.createServer();
    server.on('request',this.request.bind(this));
    server.listen(this.config.port,()=>{
        let url = `${this.config.host}:${this.config.port}`;
        debug(`start at ${chalk.green(url)}`);
    })
}

this.config.port可以自己定義端口,debug用于在控制臺(tái)打印信息。

請(qǐng)求處理方法

async request(req,res){
    //接收請(qǐng)求
    let { pathname } = url.parse(req.url);
    let filepath = path.join(this.config.root,pathname);
    try{
        let statObj = await stat(filepath);
        if(statObj.isDirectory()){//判斷是否為目錄
            //是目錄的話使用handlebars模板引擎渲染目錄
            let files = await readdir(filepath);//字符串?dāng)?shù)組
            files = files.map((file)=>{
                return {
                    name:file,
                    url:path.join(pathname,file)
                }
            });
            let html = this.list({
                title:pathname,
                files:files
            });
            res.setHeader('Content-Type','text/html');
            this.sendFile(req,res,html,statObj,'html');
        }else{
            this.sendFile(req,res,filepath,statObj,'');
        }
    }catch (e){
        debug(inspect(e));
        this.sendError(req,res)
    }
}

這個(gè)是主要處理邏輯,首先通過(guò)解析客戶端的請(qǐng)求url,通過(guò)path模塊來(lái)拿到文件路徑,第一個(gè)參數(shù)是config中配置的靜態(tài)文件根目錄;然后來(lái)判斷當(dāng)前請(qǐng)求的是文件還是目錄,這里使用一個(gè)try catch代碼塊來(lái)捕獲異常,如果請(qǐng)求的是個(gè)目錄的話,遍歷這個(gè)目錄下的所有文件并且將文件名和文件路徑傳給list編譯模板,然后交給發(fā)送方法去處理。

發(fā)送處理方法

sendFile(req,res,filepath,statObj,type){
    //發(fā)送文件
    let expires = new Date(Date.now() + 60 * 1000);
    //緩存設(shè)置
    res.setHeader('Expires', expires.toUTCString());
    res.setHeader('Cache-Control', 'max-age=600');
    res.setHeader('Accept-Range', 'bytes');//斷點(diǎn)續(xù)傳
    if(type == 'html'){
        res.end(filepath);
    }else {
        res.setHeader('Content-Type',mime.getType(filepath));
        fs.createReadStream(filepath).pipe(res);
    }
}

發(fā)送方法里設(shè)置的緩存策略為強(qiáng)制緩存,并且在發(fā)送方法里調(diào)用zlibFn方法去看客戶端請(qǐng)求是否使用壓縮,并在最后將內(nèi)容pipe到res里返回給客戶端。

zlib壓縮方法

zlibFn(req,res){
    let acceptEncoding = request.headers['accept-encoding'];//壓縮
    if (!acceptEncoding) {
        acceptEncoding = '';
    }
    if (acceptEncoding.match(/\bdeflate\b/)) {
        res.setHeader('Content-Encoding','deflate');
        return zlib.createDeflate();
    } else if (acceptEncoding.match(/\bgzip\b/)) {
        res.setHeader('Content-Encoding','gzip');
        return zlib.createGzip();
    } else {
        return null;
    }
}

這里主要是通過(guò)請(qǐng)求頭中的accept-encoding來(lái)判斷是否壓縮,以何種方式壓縮,壓縮后返回一個(gè)流對(duì)象。

初寫node靜態(tài)服務(wù)器(簡(jiǎn)易版)全部代碼請(qǐng)見(jiàn)Github

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,534評(píng)論 19 139
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,917評(píng)論 25 709
  • 2017年8月17日,如是家人蓮花遍智,種種子第17天 發(fā)心:我今不僅僅是為了我個(gè)人而聞思修,更是為了六道輪回一切...
    吳宗澤閱讀 260評(píng)論 0 2
  • 不知道怎么說(shuō)了 我想我愛(ài)上你了 和你一起時(shí) 看著你開(kāi)心 看著逗你時(shí)那可愛(ài)的表情 不喜我買東西給你 我總是說(shuō)不要我丟...
    有病的中二少年閱讀 186評(píng)論 2 0

友情鏈接更多精彩內(nèi)容