使用Node.js搭建簡單靜態(tài)文件服務(wù)器

這半個多月一直在學(xué)Node.js,還是在入門階段人乓,不過已經(jīng)對Node很感興趣了勤篮。這里介紹一個簡單的靜態(tài)文件服務(wù)器,總結(jié)一下心得體會色罚。為什么說簡單呢碰缔,因為雖然基本功能都有,但是沒加路由保屯,還有沒考慮一些安全性的東西手负。后面我會繼續(xù)來總結(jié)完善。

本文參考了Node大神樸靈11年寫的一篇博文(強烈建議讀一讀姑尺,雖然有一些接口有些老竟终,但是搭建服務(wù)器的思路,各方面都有涉及)切蟋,還有這位大神前輩的博客统捶,以及Node.js 6.x版本的文檔,stackoverflow一些答案柄粹。
如果哪里說得不對或者哪里有問題喘鸟,請勞煩您指正,我會虛心接受驻右。

正文如下:

一個Web服務(wù)器應(yīng)具備以下幾個功能:

1什黑、能顯示以.html/.htm結(jié)尾的Web頁面

2、能直接打開以.js/.css/.json/.text結(jié)尾的文件內(nèi)容

3堪夭、顯示圖片資源

4愕把、自動下載以.apk/.docx/.zip結(jié)尾的文件

5、形如http://xxx.com/a/b/ , 則查找b目錄下是否有index.html,如果有就顯示森爽,如果沒有就列出該目錄下的所有文件及文件夾恨豁,并可以進(jìn)一步訪問。

6爬迟、形如http://xxx.com/a/b, 則作301重定向到http://xxx.com/a/b/ , 這樣可以解決內(nèi)部資源引用錯位的問題橘蜜。

總體的思路如下:

1.先加載需要用到的幾個模塊 url(解析request,截取路徑) path(解析路徑) fs(文件讀寫操作) http(起服務(wù)器)

2.切出來請求的url和路徑 (記得解碼,防止中文亂碼)

3.根據(jù)路徑有無擴展名以及是否以“/”結(jié)尾作判斷付呕,重定向

4.根據(jù)路徑來查找資源文件

OK,接下來上代碼计福,我有詳細(xì)的標(biāo)注注釋(咳,方便以后來查漏補缺)

前面有提到參考的那兩篇博文的年代有些久遠(yuǎn)(其實也就4,5年前..)徽职,以致一些接口6.x版本的Node.js已經(jīng)不支持了棒搜,或者一些方法近些年有了最佳實踐。

說一下重構(gòu)的地方:
1.判斷路徑類型活箕,不使用fs.exist(),而是換成fs.stat方法

2.將回調(diào)換成了箭頭函數(shù)。

3.我一直沒查到getContentType這個方法.. 所以還是使用mime映射來傳入content-type 其實已經(jīng)專門有mime模塊來處理這個問題了育韩。

4.做了一下模塊化處理

第一個模塊: app.js 啟動模塊

"use strict";
//加載所需要的模塊
var http = require('http');

var processRequest = require('./server');

//創(chuàng)建服務(wù)克蚂,這里很機智的把對response和request的處理封裝成一個匿名函數(shù),傳入createServer中
//也可以直接在里面寫筋讨,但是看起來不是很整潔
var httpServer = http.createServer((req, res) => {
    processRequest(req, res);
});

var port = 8080;

//指定一個監(jiān)聽的接口
httpServer.listen(port, function() {

    console.log(`app is running at port:${port}`);
});

第二個模塊:mime.js 存放類型映射

module.exports = {
    "css": "text/css",
    "gif": "image/gif",
    "html": "text/html",
    "ico": "image/x-icon",
    "jpeg": "image/jpeg",
    "jpg": "image/jpeg",
    "js": "text/javascript",
    "json": "application/json",
    "pdf": "application/pdf",
    "png": "image/png",
    "svg": "image/svg+xml",
    "swf": "application/x-shockwave-flash",
    "tiff": "image/tiff",
    "txt": "text/plain",
    "wav": "audio/x-wav",
    "wma": "audio/x-ms-wma",
    "wmv": "video/x-ms-wmv",
    "xml": "text/xml"
};

第三個模塊埃叭,也是我們的核心模塊 server.js

var url = require('url');

var fs = require('fs');

var path = require('path');

var mime = require('./mime');

function processRequest(request, response) {


    //request里面切出標(biāo)識符字符串
    var requestUrl = request.url;
    //url模塊的parse方法 接受一個字符串,返回一個url對象,切出來路徑
    var pathName = url.parse(requestUrl).pathname;

    //對路徑解碼悉罕,防止中文亂碼
    var pathName = decodeURI(pathName);

    //解決301重定向問題赤屋,如果pathname沒以/結(jié)尾,并且沒有擴展名
    if (!pathName.endsWith('/') && path.extname(pathName) === '') {

        pathName += '/';
        var redirect = "http://" + request.headers.host + pathName;
        response.writeHead(301, {
            location: redirect
        });
        //response.end方法用來回應(yīng)完成后關(guān)閉本次對話壁袄,也可以寫入HTTP回應(yīng)的具體內(nèi)容类早。
        response.end();
    };

    //獲取資源文件的絕對路徑
    var filePath = path.resolve(__dirname + pathName);
    console.log(filePath);
    //獲取對應(yīng)文件的文檔類型
    //我們通過path.extname來獲取文件的后綴名。由于extname返回值包含”.”嗜逻,所以通過slice方法來剔除掉”.”涩僻,
    //對于沒有后綴名的文件,我們一律認(rèn)為是unknown栈顷。
    var ext = path.extname(pathName);
    ext = ext ? ext.slice(1) : 'unknown';

    //未知的類型一律用"text/plain"類型
    var contentType = mime[ext] || "text/plain";

    fs.stat(filePath, (err, stats) => {

        if (err) {
            response.writeHead(404, { "content-type": "text/html" });
            response.end("<h1>404 Not Found</h1>");
        };
        //沒出錯 并且文件存在
        if (!err && stats.isFile()) {

            response.writeHead(200, { "content-type": contentType });
            //建立流對象逆日,讀文件
            var stream = fs.createReadStream(filePath);
            //錯誤處理
            stream.on('error', function() {

                response.writeHead(500, { "content-type": contentType });

                response.end("<h1>500 Server Error</h1>");

            });
            //讀取文件
            stream.pipe(response);
            //response.end();  這個地方有坑,加了會關(guān)閉對話萄凤,看不到內(nèi)容了
        };
        //如果路徑是目錄
        if (!err && stats.isDirectory()) {

            var html = " <head><meta charset = 'utf-8'/></head>";
            //讀取該路徑下文件
            fs.readdir(filePath, (err, files) => {
                if (err) {
                    console.log("讀取路徑失斒页椤!");
                } else {

                    // files.foreach(function (file) {
                    // //做成一個鏈接表靡努,方便用戶訪問
                    // html+=`<div><a href="${file}">${file}</a></div>`;
                    //  });

                    for (var file of files) {
                        if (file === "index.html") {

                            response.writeHead(200, { "content-type": "text/html" });
                            response.end(file);

                            break;
                        };
                        html += `<div><a href='${file}'>${file}</a></div>`;
                        console.log(html);

                    }
                    response.writeHead(200, { "content-type": "text/html" });
                    response.end(html);
                };

            });


        };

    });

};

module.exports = processRequest;
    這里有幾個細(xì)節(jié)的地方值得注意坪圾,一個是如何判斷并實現(xiàn)重定向的,第二個是如何來判斷content-type的颤难。第三個要注意異步回調(diào)的執(zhí)行順序問題神年,有個坑就在傳html那里。
    再說一個小坑吧行嗤,response.end()這個方法我理解的不夠深已日,這個方法是用來關(guān)閉對話或者向response的body部分傳內(nèi)容,我把它放在了stream操作的下面栅屏,結(jié)果可想而知...  所以再涉及到文件讀寫時飘千,一定要注意這個地方。

下面是實現(xiàn)截圖:

1.這是我的目錄栈雳,不用管那個vscode护奈,那是visual studio code文件配置目錄

![1.png](http://upload-images.jianshu.io/upload_images/3373032-ffc04d2fc246ad97.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

2.服務(wù)器啟動在8080端口

![2.png](http://upload-images.jianshu.io/upload_images/3373032-9f44b9d0b7329c7a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
3.使用這個地址

![3.png](http://upload-images.jianshu.io/upload_images/3373032-18056b5020add779.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

4.打開調(diào)試工具,可以發(fā)現(xiàn)Head部分是301哥纫,也就是發(fā)生了重定向

![4.png](http://upload-images.jianshu.io/upload_images/3373032-8bdef90683b18238.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

5.來看看網(wǎng)頁內(nèi)容霉旗,可以看到,我們得到了該目錄下可以訪問的文件條目

![5.png](http://upload-images.jianshu.io/upload_images/3373032-cb9c9e1934c412ef.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

6.最后,控制臺信息

![6.png](http://upload-images.jianshu.io/upload_images/3373032-421376c5ef9f7914.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


OK  就是這樣厌秒。歡迎收看你的月亮我的心读拆,好男人就是我~ 我們下周同一時間再會~
PS:如果本文有錯誤的地方請您一定要指出來,我會虛心接受鸵闪,萬分感謝檐晕。~~
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市蚌讼,隨后出現(xiàn)的幾起案子辟灰,更是在濱河造成了極大的恐慌,老刑警劉巖篡石,帶你破解...
    沈念sama閱讀 222,627評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件芥喇,死亡現(xiàn)場離奇詭異,居然都是意外死亡夏志,警方通過查閱死者的電腦和手機乃坤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來沟蔑,“玉大人湿诊,你說我怎么就攤上這事∈莶模” “怎么了厅须?”我有些...
    開封第一講書人閱讀 169,346評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長食棕。 經(jīng)常有香客問我朗和,道長,這世上最難降的妖魔是什么簿晓? 我笑而不...
    開封第一講書人閱讀 60,097評論 1 300
  • 正文 為了忘掉前任眶拉,我火速辦了婚禮,結(jié)果婚禮上憔儿,老公的妹妹穿的比我還像新娘忆植。我一直安慰自己,他們只是感情好谒臼,可當(dāng)我...
    茶點故事閱讀 69,100評論 6 398
  • 文/花漫 我一把揭開白布朝刊。 她就那樣靜靜地躺著,像睡著了一般蜈缤。 火紅的嫁衣襯著肌膚如雪拾氓。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,696評論 1 312
  • 那天底哥,我揣著相機與錄音咙鞍,去河邊找鬼房官。 笑死,一個胖子當(dāng)著我的面吹牛续滋,可吹牛的內(nèi)容都是我干的易阳。 我是一名探鬼主播,決...
    沈念sama閱讀 41,165評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼吃粒,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了拒课?” 一聲冷哼從身側(cè)響起徐勃,我...
    開封第一講書人閱讀 40,108評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎早像,沒想到半個月后僻肖,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,646評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡卢鹦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,709評論 3 342
  • 正文 我和宋清朗相戀三年臀脏,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片冀自。...
    茶點故事閱讀 40,861評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡揉稚,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出熬粗,到底是詐尸還是另有隱情搀玖,我是刑警寧澤,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布驻呐,位于F島的核電站灌诅,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏含末。R本人自食惡果不足惜猜拾,卻給世界環(huán)境...
    茶點故事閱讀 42,196評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望佣盒。 院中可真熱鬧挎袜,春花似錦、人聲如沸沼撕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,698評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽务豺。三九已至磨总,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間笼沥,已是汗流浹背蚪燕。 一陣腳步聲響...
    開封第一講書人閱讀 33,804評論 1 274
  • 我被黑心中介騙來泰國打工娶牌, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人馆纳。 一個月前我還...
    沈念sama閱讀 49,287評論 3 379
  • 正文 我出身青樓诗良,卻偏偏與公主長得像,于是被迫代替她去往敵國和親鲁驶。 傳聞我的和親對象是個殘疾皇子鉴裹,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,860評論 2 361

推薦閱讀更多精彩內(nèi)容

  • 個人入門學(xué)習(xí)用筆記、不過多作為參考依據(jù)钥弯。如有錯誤歡迎斧正 目錄 簡書好像不支持錨點径荔、復(fù)制搜索(反正也是寫給我自己看...
    kirito_song閱讀 2,479評論 1 37
  • Node.js是目前非常火熱的技術(shù)脆霎,但是它的誕生經(jīng)歷卻很奇特总处。 眾所周知,在Netscape設(shè)計出JavaScri...
    w_zhuan閱讀 3,617評論 2 41
  • Node.js是目前非尘χ耄火熱的技術(shù)鹦马,但是它的誕生經(jīng)歷卻很奇特。 眾所周知忆肾,在Netscape設(shè)計出JavaScri...
    Myselfyan閱讀 4,076評論 2 58
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理荸频,服務(wù)發(fā)現(xiàn),斷路器难菌,智...
    卡卡羅2017閱讀 134,715評論 18 139
  • 文|愛讀分享者 自從這部韓劇襲來试溯,顏值擔(dān)當(dāng)?shù)乃沃倩蛽軇恿巳f千追劇少女的心弦,成了諸多“韓粉”最新的“舔屏對象”郊酒。...
    愛讀分享閱讀 525評論 0 0