express中間件,一篇文章就夠了

底層: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迴應的requestresponse對象

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.useapp.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');
})

$ node app
result

如果我們想要處理掛在至/user/:id的中間件的GET請求,我們需要使用next()request對象傳遞給下一個中間件

否者:
error 得不到下一個中間件處理的它,一直在等待...

最終會拋出localhost未發送任何數據的錯誤
error

如何你不想要終止請求-響應循環,總是記得通過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())


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章