底層:http模塊
express目前是最流行的基於Node.js的web開發框架,express框架建立在內置的http模塊上,
var http = require('http')
var app = http.createServer(function(req,res){
res.writeHead(200,{"Content-type":"text/plain"});
res.end('hello world')
})
app.listen(3000,'lcoalhost')
上面代碼的關鍵是使用createServer
方法,生成一個HTTP的服務器實例。該方法接受一個回調函數,回調函數的參數分別代表HTTP請求和HTTP回應的request
和response
對象
Experss框架的核心是對http模塊的再包裝,
var express = require('express')
var port = process.env.PORT || 3000
var app = express()
app.get('/',fcuntion(req,res){
res.send('hello world')
})
app.listen(port)
比較http.createServer()
方法創建一個app實例和Express的構造方法,生成一個Express實例,兩者的回調函數都是相同的。Express框架等於在http模塊之上,加了一個中間層
中間件
Express是一個自身功能極簡單,完全由路由
和中間件
構成的web開發框架,從本質上說,一個Express應用是在調用各種中間件
中間件(middleware)
是一個函數,他可以訪問請求對象(request object(req)),響應對象(response object(res))和web應用中處於請求-響應循環
Express可以使用如下幾種中間件:
- 應用級中間件
- 路由級中間件
- 錯誤處理中間件
- 內置中間件
- 第三方中間件
應用級中間件
應用級中間鍵綁定到app對象
使用app.use
和app.METHOD()-需要處理http請求的方法,例如GET、PUT、POST
var app = express()
// 沒有掛載路徑的中間件,應用中的每個請求都會執行該中間件
app.use((req,res,next) => {
console.log('Time',Dtae.now());
next(); // 傳遞request對象給下一個中間件
})
// 掛載至/user/:id的中間件,任何執行/user/:id的請求都會執行它
app.use('/use/:id',(req,res,next) => {
console.log('Request Type',req.method);
next();
})
// 路由和句柄函數(中間件系統),處理指向/user/:id的GET請求
app.get('/user/:id',(req,res,next)=>{
console.log('USER');
})
如果我們想要處理掛在至/user/:id
的中間件的GET請求,我們需要使用next()
將request
對象傳遞給下一個中間件
否者:
得不到下一個中間件處理的它,一直在等待...
最終會拋出localhost未發送任何數據的錯誤
如何你不想要終止請求-響應循環
,總是記得通過next()
傳遞request對象
如果你想要在中間件棧中跳過剩余中間件,調用next('route')方法將控制權交給下一個路由
app.get('/user/:id',(req,res,next)=>{
if(req.params.id==0) next('route')
else next()
},(req,res,next)=>{
// 渲染常規頁面
res.render('regular')
})
// 處理/user/:id,渲染一個id為0的特殊頁面
app.get('/user/:id',(req,res,next)=>{
res.render('special')
})
路由級中間件
路由級中間件和應用級中間件類似,只不過是它綁定對象為express.Router()
var router = express.Router()
路由級使用router.use()
或router.VERB()
加載
舉個栗子
var app = express()
var router = express.Router()
// 沒有掛載路徑的中間件,通過該路由的每個請求都會執行該中間件
router.use(function (req, res, next) {
console.log('Time:', Date.now());
next();
})
// 一個中間件,顯示任何指向/user/:id的HTTP請求的信息
router.use('/user/:id',(req,res,next)=>{
console.log('Request URL',req.originalUrl)
next()
},(req,res,next)=>{
console.log('Request Type',req.method)
next()
})
// 一個中間件棧,處理指向/user/:id的GET請求
router.get('/user/:id',(req,res,next)=>{
if(req.params.id == 0) next('router')
else next()
},(req,res,next)=>{
res.render('regular')
})
// 處理/user/:id,渲染一個特殊頁面
router.get('user/:id',(req,res,next)=>{
console.log(req.params.id)
res.render('special')
})
// 將路由掛載至應用
app.use('/',router)
錯誤處理中間件
錯誤處理中間件有四個參數,定義錯誤處理中間件必須使用這四個參數。即使不需要next對象,也必須在參數中聲明它,否者中間件會識別為一個常規中間件,不能處理錯誤
舉個栗子:
app.use((err,req,res,next)=>{
console.error(err.stack)
res.status(500).send('Something broke')
})
中間件返回的響應是隨意的,可以響應一個 HTML 錯誤頁面、一句簡單的話、一個 JSON 字符串,或者其他任何您想要的東西。
所以你可能想要像處理常規中間件那樣,定義多個錯誤處理中間件
,比如您想為使用 XHR 的請求定義一個,還想為沒有使用的定義一個,那么:
app.use(logErrors)
app.use(clientErrorHandler)
app.use(errorHandler)
logErrors
將請求和錯誤信息寫入標准錯誤輸出、日志或者類似服務
function logErrors(err,req,res,next){
console.error(err.stack)
next(err)
}
clientErrorHandler
定義如下(這里將錯誤直接傳給了next)
function clientErrorHandler(err,req,res,next){
if(req.xhr){
res.status(500).send({error:'Something blew up!'})
}else{
next(err)
}
}
errorHandler
捕獲所有錯誤
function errorHandler(err,req,res,next){
res.status(500)
res.render('error',{error:err})
}
內置中間件
從版本4.x開始,Express不再依賴Content
,除了 express.static
, Express 以前內置的中間件現在已經全部單獨作為模塊安裝使用
express.static
是 Express 唯一內置的中間件。
它基於 serve-static
,負責在 Express 應用中提托管靜態資源。
可選options
參數擁有如下屬性
屬性 | 描述 | 類型 | 缺省值 |
---|---|---|---|
dotfiles | 是否對外輸出文件名以點(.)開頭的文件。可選值為 “allow”、“deny” 和 “ignore” | String | "ignore" |
etag | 是否啟用etag生成 | Boolean | true |
extensions | 設置文件擴展名備份選項 | Array | [ ] |
index | 發送目錄索引文件,設置為 false 禁用目錄索引。 | mixed | "index.html" |
lastModified | 設置 Last-Modified 頭為文件在操作系統上的最后修改日期 | Boolean | true |
maxAge | 毫秒或者其字符串格式設置 Cache-Control 頭的 max-age 屬性 | Number | 0 |
redirect | 當路徑為目錄時,重定向至"/" | Boolean | true |
setHeaders | 設置HTTP頭以提供文件的函數 | Function |
下面的栗子使用了 express.static
中間件,其中的 options
對象經過了精心的設計。
var options = {
dotfiles: 'ignore',
etag: false,
extensions: ['htm', 'html'],
index: false,
maxAge: '1d',
redirect: false,
setHeaders: function (res, path, stat) {
res.set('x-timestamp', Date.now());
}
}
app.use(express.static('public', options));
我們總是需要使用express.static
指定多個靜態資源文件,比如:
app.use(express.static('public'))
app.use(express.static('files'))
第三方中間件
通過使用第三方中間件從而為Express應用增加更多的功能
安裝所需功能的node模塊,並在應用中加載,可以在應用級中加載,也可以在路由級中加載
舉個栗子
$ npm install cookie-parser
var express = require('express')
var app = express()
var cookieParser = require('cookie-parser')
// 加載用於解析cookie的中間件
app.use(cookieParser())
參考資料