摘要:在項(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.js中route()方法的實(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 += "
小結(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
摘要:在項(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); ...
摘要:但是為什么執(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...
摘要:面向?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ì)...
閱讀 3475·2021-11-25 09:43
閱讀 1081·2021-11-15 11:36
閱讀 3325·2021-11-11 16:54
閱讀 3992·2021-09-27 13:35
閱讀 4381·2021-09-10 11:23
閱讀 5788·2021-09-07 10:22
閱讀 3050·2021-09-04 16:40
閱讀 779·2021-08-03 14:03