Express實用技巧和設計模式
1.Express介紹
Express是一個簡介贺氓、靈活的node.js web應用開發(fā)框架蝶糯,是目前最流行的基于node.js的web開發(fā)框架璃氢,提供了一系列強大的功能,比如:
- 路由控制
- 中間件
- 靜態(tài)文件服務
- 模板解析
本文主要介紹這些功能的使用和它的設計理念
2.Express如何使用
本地安裝
$ npm install express
獲取及刻、引用通過變量app(app其實在內(nèi)部是application返回的一個handle函數(shù)美澳,所有express的方法都在app上的原型方法) 我們可以調(diào)用express的方法
var express = require('express)
var app = express()
app.liten(3000)
3.路由控制
express通過匹配請求路徑,在做request眠饮、response操作奥帘,具體看下面get、post方法
-
Express的get方法
第一個參數(shù)path為請求路徑仪召,第二個參數(shù)為處理請求的回調(diào)函數(shù)
app.get(path, function(req, res))
get方法使用
const express = require('express'); const app = express(); //匹配htp://localhost:3000/hello做相關req翩概,res的操作 app.get('/hello',function(req,res){ res.end('hello'); }); //匹配htp://localhost:3000/world做相關req,res的操作 app.get('/world',function(req,res){ res.end('world'); }); //匹配所有返咱,主要用作not found app.get('*',function(req,res){ res.setHeader('Content-Type','text/plain;charset=utf8'); res.end('Not Found'); }); app.listen(3000);
-
Express的post方法
第一個參數(shù)path為請求路徑,第二個參數(shù)為處理請求的回調(diào)函數(shù)和get一樣
app.post(path,function(req,res))
post方法使用
var express = require('./express'); var app = express(); //匹配htp://localhost:3000/hello做相關req牍鞠,res的操作 app.post('/hello', function (req,res) { res.end('hello'); }); //匹配所有咖摹,主要用作not found app.post('*', function (req,res) { res.end('post沒找到'); }); app.listen(3000);
通過linux命令發(fā)送post請求
$ curl -X POST http://localhost:3000/hello
-
Express的all方法
監(jiān)聽所有的請求方法,可以匹配所有的HTTP動詞难述。根據(jù)請求路徑來處理客戶端發(fā)出的所有請求萤晴,參數(shù)同上
app.all(path,function(req, res))
all方法使用
const express = require('express'); const app = express(); app.all('/world',function(req,res){ res.end('all world'); }); app.listen(3000);
-
Express Router的設計理念
先看如下代碼
const express = require('express'); const app = express(); app.get('/user',function(req,res,next){ console.log(1); next(); },function(req,res,next){ console.log(11); next(); }).get('/world',function(req,res,next){ console.log(2); next(); }).get('/hello',function(req,res,next){ console.log(3); res.end('ok'); }); app.listen(3000);
如上代碼,體現(xiàn)出express router的一個概念胁后,就是二維數(shù)組的二維數(shù)據(jù)形式店读,這個概念的主要意義是:在router路由容器中存放一層層route實例,并且每層route實例中存放一層層callback攀芯,當匹配上一個route的時候屯断,執(zhí)行它里面的callback
如下圖所示
再router和route中分別用stack存儲,不同的是Router中的stack存放的是Route侣诺,并且根據(jù)相同路由匹配殖演,遍歷Stack中相關Route,其中handle方法是掛載到layer上面的Route年鸳,并且觸發(fā)Route從而遍歷Route中的Stack趴久,在Route中的Stack存放的是一層層的callback,所以最終調(diào)用所有callback在同一個匹配路徑上搔确,其中核心原理就是這個二維數(shù)組的二維數(shù)據(jù)形式
4.中間件
中間件就是處理HTTP請求的函數(shù)彼棍,用來完成各種特定的任務,比如檢查用戶是否登錄膳算、檢測用戶是否有權限訪問等座硕,它的特點是:
一個中間件處理完請求和響應可以把相應數(shù)據(jù)再傳遞給下一個中間件
回調(diào)函數(shù)的next參數(shù),表示接受其他中間件的調(diào)用,函數(shù)體中的next(),表示將請求數(shù)據(jù)繼續(xù)傳遞
可以根據(jù)路徑來區(qū)分返回執(zhí)行不同的中間件
-
1.中間件的使用
主要通過use方法
var express = require('express'); var app = express(); app.use(function (req,res,next) { console.log('全部匹配'); next(); }); app.use('/water', function (req,res,next) { console.log('只匹配/water'); next(); }); app.get('/water', function (req,res) { res.end('water'); }); app.listen(3000);
2.中間件原理
通過Application原型上的use方法涕蜂,將Router變函數(shù)坎吻,抽象出Router方法復用,Router處理中間件宇葱,其實就是上面所講述的路由控制原理瘦真,看如下代碼刊头,可以用app下面的use方法調(diào)取中間件,也可以創(chuàng)建一個express.router诸尽,在通過app下面use調(diào)用這個中間件原杂,形成一個父子級別的中間件路由,下面user.use就是當訪問/user/或者/user/2的子路由
const express = require('../'); const app = express(); app.use(function(req,res,next){ console.log('Ware1:',Date.now()); next('wrong'); }); app.get('/',function(req,res,next){ res.end('1'); }); const user = express.Router(); user.use(function(req,res,next){ console.log('Ware2',Date.now()); next(); }); user.use('/2',function(req,res,next){ res.end('2'); }); app.use('/user',user); app.use(function(err,req,res,next){ res.end('catch '+err); }); app.listen(3000,function(){ console.log('server started at port 3000'); });
3.中間件設計模式
主要思想就是Application有一個router屬性指向了Router函數(shù)您机,在Router中返回一個router函數(shù)穿肄,將get/handle等方法掛載到返回的router上面,其實express.Router()方法就是Router函數(shù)际看。并且中間件和普通的路由都是在Router的stack中咸产,如圖所示
5.靜態(tài)服務文件
如果要在網(wǎng)頁中加載靜態(tài)文件(css、js仲闽、img)脑溢,就需要另外指定一個存放靜態(tài)文件的目錄,當瀏覽器發(fā)出非HTML文件請求時赖欣,服務器端就會到這個目錄下去尋找相關文件
var express = require('express');
var app = express();
var path = require('path');
app.use(express.static(path.join(__dirname,'public')));
app.listen(3000);
-
靜態(tài)文件服務器實現(xiàn)
static屬于express內(nèi)置中間件屑彻,其中原理主要是調(diào)用了serve-static庫,具體實現(xiàn)是原生node.js API顶吮,可以查看我寫的一篇如何搭建靜態(tài)服務器 static-server
6.模板解析
這里主要說的是ejs模板社牲,具體API請查閱 EJS官網(wǎng)
-
安裝ejs
$ npm install ejs
-
設置模板
var express = require('express'); var path = require('path'); var app = express(); app.set('view engine','ejs'); app.set('views',path.join(__dirname,'views')); app.listen(3000);
-
渲染html
app.set('view engine','html') app.set('views',path.join(__dirname,'views')); app.engine('html',require('ejs').__express);
-
渲染視圖
- 第一個參數(shù) 要渲染的模板
- 第二個參數(shù) 渲染所需要的數(shù)據(jù)
app.get('/', function (req,res) { res.render('hello',{title:'hello'},function(err,data){}); });
-
模板的實現(xiàn)
res.render = function (name, data) { var viewEngine = engine.viewEngineList[engine.viewType]; if (viewEngine) { viewEngine(path.join(engine.viewsPath, name + '.' + engine.viewType), data, function (err, data) { if (err) { res.status(500).sendHeader().send('view engine failure' + err); } else { res.status(200).contentType('text/html').sendHeader().send(data); } }); } else { res.status(500).sendHeader().send('view engine failure'); } }
7.結語
本篇文章主要介紹核心功能和核心代碼思想,其余的方法如:redirect(重定向)悴了、body-parser(請求體解析)搏恤、send方法等等不做介紹,具體請查閱下方給出的相關教程
8.博客
有任何問題可留言或者發(fā)送本人郵箱ngaiwe@126.com