成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

Node.js開(kāi)發(fā)系列(六)

Jiavan / 788人閱讀

摘要:在項(xiàng)目的文件夾下完成安裝依賴(lài)項(xiàng)。的主要功能是負(fù)責(zé)創(chuàng)建一個(gè)服務(wù),然后對(duì)請(qǐng)求的路由進(jìn)行判斷和過(guò)濾,交由模塊進(jìn)行處理具體的請(qǐng)求路由。

上一節(jié)我們實(shí)現(xiàn)了手動(dòng)控制路由的示例,這節(jié)我們來(lái)做一個(gè)完整的示例

目錄結(jié)構(gòu)
基于前面的一些鋪墊,這節(jié)會(huì)做一個(gè)完整的示例。目錄的文件結(jié)構(gòu)如下 :


 - node-express-pug ==>項(xiàng)目目錄

 - package.json ==>依賴(lài)文件

 - server.js ==> 入口文件
 
 - start.js ==> 創(chuàng)建服務(wù)
 
 - router.js   ==>  路由中轉(zhuǎn)
 
 - handlers.js  ==> 路由處理
 
 - views/home.html ==>首頁(yè)
 
 - files/ ==>存放上傳文件的目錄

 - node_modules/ ==>依賴(lài)項(xiàng)文件目錄
 

package.json
首先我們安裝依賴(lài)項(xiàng),本示例中的package.json文件如下:

{
  "name": "application-name",
  "version": "0.0.1",
  "dependencies": {
    "formidable": "latest",
    "mime": "~1.3.4"
  }
}

其中,formidable用于處理form表單數(shù)據(jù),mime是一個(gè)互聯(lián)網(wǎng)標(biāo)準(zhǔn)類(lèi)型,通過(guò)設(shè)定它就可以設(shè)定文件在瀏覽器的打開(kāi)方式。稍后我們會(huì)看到如何使用它們。在項(xiàng)目的文件夾下npm install完成安裝依賴(lài)項(xiàng)。

server.js
首先我們來(lái)實(shí)現(xiàn)server.js。在server.js中,我們主要實(shí)現(xiàn)服務(wù)器的入口功能,調(diào)用各個(gè)模塊組件,由其他模塊實(shí)現(xiàn)具體的功能。

var server = require("./start");
var router = require("./router");
var handlers = require("./handlers");

var handler = {};
handler[["/","GET"]] = handlers.home;
handler[["/show","GET"]] = handlers.show;
handler[["/upload","POST"]] = handlers.upload;

server.start(router.route,handler);

先導(dǎo)入我們創(chuàng)建的其他的模塊文件,然后定義一個(gè)handlder對(duì)象,這里配置了對(duì)應(yīng)的路由路徑和其對(duì)應(yīng)的處理方法,類(lèi)似handler[["/","GET"]] = handlers.home;,然后又調(diào)用了server模塊的start()方法,并傳入兩個(gè)參數(shù),分別是router.route方法和handler對(duì)象。下面我們就來(lái)實(shí)現(xiàn)start.js文件。

start.js
start.js的主要功能是負(fù)責(zé)創(chuàng)建一個(gè)server服務(wù),然后對(duì)請(qǐng)求的路由進(jìn)行判斷和過(guò)濾,交由router模塊進(jìn)行處理具體的請(qǐng)求路由。完整的代碼如下

//1.引用模塊
var http = require("http");
var url = require("url");
var formidable = require("formidable");
var querystring = require("querystring");

//2.start(route,handler)方法
//方法的參數(shù)是由上層傳遞過(guò)來(lái),分別是router.route方法和handler對(duì)象
//其中route負(fù)責(zé)處理路由
//handler對(duì)象里是我們預(yù)先定義的可用處理的路由和對(duì)應(yīng)的請(qǐng)求類(lèi)型
function start(route,handler) {
    console.log("Start Begin");
    
    //3.監(jiān)聽(tīng)1337端口,創(chuàng)建服務(wù)器
    var port = process.env.port || 1337;
    http.createServer(onRequest).listen(port);

    //4.創(chuàng)建服務(wù)器的回調(diào)方法
    function onRequest(req, res) {
        console.log("Request Begin");
        //解析請(qǐng)求的路徑名
        var pathname = url.parse(req.url).pathname; 

        var query = url.parse(req.url).query;
        //POST方法處理
        if (req.method === "POST"){
            //解析form表單POST方式提交數(shù)據(jù)
            var form = new formidable.IncomingForm();
             //解析路徑的請(qǐng)求參數(shù),包裝成data向下傳遞
             //function (err, fields, files)是解析成功的回調(diào)方法
            form.parse(req, function (err, fields, files) {
                if (err){
                    console.error(err.message);
                    return;
                }
                var data = {fields:fields, files:files};
                execute(pathname,handler,req, res, data);
            });
        }
        //GET方法處理請(qǐng)求
        if (req.method === "GET"){
            var data = {
            //解析路徑的請(qǐng)求參數(shù),包裝成data向下傳遞
                fields: querystring.parse(query)
            };
            execute(pathname,handler,req, res, data);
        }
        console.log("Request End");
    }
    
    //5.執(zhí)行處理后的請(qǐng)求
    function execute(pathname, handler, req, res, data) {
        //route執(zhí)行返回值,如果發(fā)生錯(cuò)誤,統(tǒng)一返回400
        var content = route(pathname,handler,req,res,data);
        if (!content){
            res.writeHead("400",{
                "Content-Type":"text/plain"
            });
            console.log(req.url);
            res.write("400 Bad Request");
            res.end();
        }
    }
}

//6.導(dǎo)出模塊
exports.start = start;

這里注意

var form = new formidable.IncomingForm();
form.parse(req, function (err, fields, files) { });

form.parse會(huì)解析出很多的屬性,傳給回調(diào)參數(shù)files,下面是一個(gè)我上傳文件后打印的請(qǐng)求參數(shù),參考如下:

{ fields: {},
  files:
   { fn:
      File {
        domain: null,
        _events: {},
        _eventsCount: 0,
        _maxListeners: undefined,
        size: 4510,
        path: "C:UsersADMINI~1AppDataLocalTempupload_5990006963ce4f2
9de485ddadd819355",
        name: "sql.sql",
        type: "application/octet-stream",
        hash: null,
        lastModifiedDate: 2017-03-10T07:00:14.577Z,
        _writeStream: [Object] 
      } 
    } 
}

router.js
我們看到最后的處理交給了var content = route(pathname,handler,req,res,data);,那么下面我們就來(lái)看router.jsroute()方法的實(shí)現(xiàn),完整的router.js如下:

function route(pathname,handler,req,res,data) {
    console.log("Route");
    var method = req.method;
    if (typeof handler[[pathname,method]] === "function"){
        return handler[[pathname,method]](res, data);
    }else {
        console.log("No Method found for " + pathname);
        return null;
    }
}

exports.route = route;

還記得我們的handler對(duì)象的格式嗎?我們的參數(shù)傳入了解析后的pathname,在這里又解析了請(qǐng)求的方式var method = req.method;typeof handler[[pathname,method]] === "function",如果請(qǐng)求路由和請(qǐng)求不在我們的handler對(duì)象的中,即沒(méi)有指定的方法調(diào)用,那么我們就直接返回null,如果有,就調(diào)用這個(gè)方法。打個(gè)比方handler[["/show","get"]](res, data)等同于handlers.show(res, data)。

home.html
在home.html中我們定義了簡(jiǎn)單的form表單,實(shí)現(xiàn)一個(gè)上傳文件的功能。

其中上傳文件的input標(biāo)簽的name="fn".




    
    HOME


    

This is Home

File Manager


Show All Files

handlers.js
這里才是我們對(duì)各個(gè)正確路由的響應(yīng)。以下是完整的代碼,我會(huì)逐一解釋說(shuō)明。

//1.引入模塊
var fs = require("fs");
var path = require("path");
var mime = require("mime");

//2.home方法,即瀏覽器請(qǐng)求`http://127.0.0.1:1337`的方法
//這里我們直接讀取views/home.html文件,返回將頁(yè)面展現(xiàn)出來(lái)
function home(res, data) {
    fs.readFile("views/home.html", function (err, data) {
        res.writeHead(200, {"Content-Type": "text/html"});
        //注意這里的data并不是home的參數(shù),而是讀取文件成功后的回調(diào)data
        res.write(data);
        res.end();
    });
    return true;
}

//3.show方法 
//show方法會(huì)處理兩種類(lèi)型的請(qǐng)求,兩種類(lèi)型的請(qǐng)求都是get類(lèi)型
//data.fields && data.fields["fn"] 這里處理的有上傳的文件后,點(diǎn)擊文件的鏈接下載文件
function show(res, data) {
    //解析參數(shù)的data的值,這里用fn是因?yàn)楹竺鎓orm表單中定義的值是fn
    if (data.fields && data.fields["fn"]){
        //獲取文件名稱(chēng)
        var name = data.fields["fn"];
        //取得文件完整名稱(chēng)
        var file = path.join(__dirname, "/files", name);
        //通過(guò)文件名指定mime類(lèi)型
        var mimeType = mime.lookup(file);
        //設(shè)定響應(yīng)頭
        res.setHeader("Content-disposition","attachment;filename=" + name);
        res.setHeader("Content-Type",mimeType);
        //讀取文件數(shù)據(jù)
        var fileData = fs.readFileSync(file,"binary");
        //響應(yīng)給給用戶(hù)
        res.end(fileData, "binary");
        
        //這里會(huì)直接返回,并不會(huì)走下面的方法
        return true;
    }

    //如果用戶(hù)不是點(diǎn)擊的下載鏈接進(jìn)行show方法
    //那么就讀取文件列表顯示在界面上,并且提供下載功能
    fs.readdir("files", function (err, list) {
        console.log(list);
        res.writeHead(200, {"Content-Type": "text/html"});
        var html = "" +
            "

File Manager

"; //有文件就生成文件列表 if (list.length) { html += "
    "; for (i = 0; i < list.length; i++) { html += "
  • " + list[i] + "
  • "; } html += "
"; } else { //沒(méi)有文件 html += "

No files found

"; } html += ""; res.write(html); res.end(); }); return true; } //4.上傳文件的方法,方法是響應(yīng)home.html中的form表單 function upload(res, data) { var temp = data.files["fn"].path; var name = data.files["fn"].name; //調(diào)用復(fù)制文件的方法 copyFile(temp,path.join("./files",name),function (err) { if (err){ console.log(err); return false; }else { return true; } }); } //定義復(fù)制文件的方法 function copyFile(source, target, callback) { //讀文件流 var rs = fs.createReadStream(source); rs.on("error",function (err) { callback(err); }); //寫(xiě)文件流 var ws = fs.createWriteStream(target); ws.on("error",function (err) { callback(err); }); ws.on("finish",function () { callback(); }); //寫(xiě)入,并覆蓋源文件的內(nèi)容 rs.pipe(ws); } //導(dǎo)出方法 exports.home = home; exports.show = show; exports.upload = upload;

小結(jié)
在項(xiàng)目文件夾下node server啟動(dòng)http服務(wù)器,在瀏覽器中輸入http://127.0.0.1:1337

在上傳文件后點(diǎn)擊Show All Files,可以看到文件列表,點(diǎn)擊其中一個(gè),即可下載。

這樣我們就完成了一個(gè)完整的node處理表單,文件上傳和下載的示例。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/86889.html

相關(guān)文章

  • Node.js開(kāi)發(fā)系列

    摘要:在項(xiàng)目的文件夾下完成安裝依賴(lài)項(xiàng)。的主要功能是負(fù)責(zé)創(chuàng)建一個(gè)服務(wù),然后對(duì)請(qǐng)求的路由進(jìn)行判斷和過(guò)濾,交由模塊進(jìn)行處理具體的請(qǐng)求路由。 上一節(jié)我們實(shí)現(xiàn)了手動(dòng)控制路由的示例,這節(jié)我們來(lái)做一個(gè)完整的示例 目錄結(jié)構(gòu) 基于前面的一些鋪墊,這節(jié)會(huì)做一個(gè)完整的示例。目錄的文件結(jié)構(gòu)如下 :showImg(https://segmentfault.com/img/bVKraD?w=186&h=214); ...

    tracy 評(píng)論0 收藏0
  • WebAssembly 系列(一)生動(dòng)形象地介紹 WebAssembly

    摘要:但是為什么執(zhí)行的更快呢在這個(gè)系列文章中,我會(huì)為你解釋這一點(diǎn)。所以當(dāng)人們說(shuō)更快的時(shí)候,一般來(lái)講是與相比而言的。被人們廣為傳播的性能大戰(zhàn)在年打響。性能的提升使得的應(yīng)用范圍得到很大的擴(kuò)展。現(xiàn)在通過(guò),我們很有可能正處于第二個(gè)拐點(diǎn)。 作者:Lin Clark 編譯:胡子大哈 翻譯原文:http://huziketang.com/blog/posts/detail?postId=58ce8036...

    wangbjun 評(píng)論0 收藏0
  • 大前端2018現(xiàn)在上車(chē)還還得及么

    摘要:面向?qū)ο笕筇卣骼^承性多態(tài)性封裝性接口。第五階段封裝一個(gè)屬于自己的框架框架封裝基礎(chǔ)事件流冒泡捕獲事件對(duì)象事件框架選擇框架。核心模塊和對(duì)象全局對(duì)象,,,事件驅(qū)動(dòng),事件發(fā)射器加密解密,路徑操作,序列化和反序列化文件流操作服務(wù)端與客戶(hù)端。 第一階段: HTML+CSS:HTML進(jìn)階、CSS進(jìn)階、div+css布局、HTML+css整站開(kāi)發(fā)、 JavaScript基礎(chǔ):Js基礎(chǔ)教程、js內(nèi)置對(duì)...

    stormgens 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<