中間件函數(shù)能夠訪問請求對象 (req)、響應(yīng)對象 (res) 以及應(yīng)用程序的請求/響應(yīng)循環(huán)中的下一個中間件函數(shù)四濒。下一個中間件函數(shù)通常由名為next
的變量來表示。
中間件函數(shù)可以執(zhí)行以下任務(wù):
- 執(zhí)行任何代碼。
- 對請求和響應(yīng)對象進行更改存哲。
- 結(jié)束請求/響應(yīng)循環(huán)母蛛。
- 調(diào)用堆棧中的下一個中間件函數(shù)翩剪。
如果當(dāng)前中間件函數(shù)沒有結(jié)束請求/響應(yīng)循環(huán),那么它必須調(diào)用next()
函數(shù)彩郊,以將控制權(quán)傳遞給下一個中間件函數(shù)前弯。否則蚪缀,請求將保持掛起狀態(tài)。
演示示例:
/**
* express 中間件使用解析
*/
const express = require('express')
// 本次 http 請求的實例
const app = express()
// 模擬登陸驗證
function loginCheckSuccess(req, res, next) {
console.log('模擬登陸成功')
setTimeout(() => {
next()
})
}
// 模擬登陸失敗
function loginCheckFailed(req, res, next) {
console.log('模擬登陸失敗')
setTimeout(() => {
res.json({
errno: -1,
msg: '登陸失敗'
})
})
}
app.use((req, res, next) => {
console.log('請求開始···', req.method, req.url)
next()
})
app.use((req, res, next) => {
// 假設(shè)在處理 cookie
req.cookie = {
userID: 'abc123'
}
next()
})
app.use((req, res, next) => {
// 假設(shè)處理 post data
// 異步
setTimeout(() => {
req.body = {
a: 100,
b: 200
}
next()
})
})
app.use('/api', (req, res, next) => {
console.log('處理 /api 路由')
next()
})
app.get('/api', (req, res, next) => {
console.log('get /api 路由')
next()
})
app.post('/api', (req, res, next) => {
console.log('get /api 路由')
next()
})
app.get('/api/get-cookie', loginCheckSuccess, (req, res, next) => {
console.log('get /api/get-cookie')
res.json({
errno: 0,
data: req.cookie
})
})
app.post('/api/get-post-deta', loginCheckFailed, (req, res, next) => {
console.log('post /api/get-post-data')
res.json({
error: 0,
data: res.body
})
})
app.use((req, res, next) => {
console.log('處理 404')
res.json({
error: -1,
msg: '404 not found'
})
})
app.listen(3000, () => {
console.log('server is running on 3000')
})
通過瀏覽器分析get請求
這里使用應(yīng)用層中間件為例恕出,解釋中間件的使用
- 首先調(diào)用
app.use()
函數(shù)的中間件询枚,將能夠響應(yīng)任何方法的請求。app.method()
函數(shù)將處理對應(yīng)HTTP方法的請求 - 如果第一個參數(shù)沒有傳入路徑參數(shù)浙巫,將默認解釋為根路徑(
/
) - 支持傳入多個中間件函數(shù)金蜀,但為了提高代碼的可讀性,盡量不要超過三個
- 首先
nodex index.js
運行上面的代碼 - 在瀏覽器中輸入
localhost:3000/api/get-cookie
- 瀏覽器返回:
{"errno":0,"data":{"userID":"abc123"}}
我們再查看控制臺中的輸出
$ node index.js
server is running on 3000
請求開始··· GET /api/get-cookie
處理 /api 路由
模擬登陸成功
get /api/get-cookie
讓我們來借此分析一下的畴,中間件的運行渊抄。
首先,app.use((req, res, next)...
苗傅,這里是通過app.use
注冊的抒线,并且沒有指定響應(yīng)路由參數(shù),默認為/
渣慕,將響應(yīng)系統(tǒng)的所有路由和方式的請求嘶炭,所以先輸出了這里定義的回調(diào)函數(shù)(請求開始··· GET /api/get-cookie
)。
其次逊桦,是第二個使用app.use()
的定義的函數(shù)眨猎,定義了req.cookie
app.use((req, res, next) => {
// 假設(shè)在處理 cookie
req.cookie = {
userID: 'abc123'
}
next()
})
再次,由于我們訪問的地址為/api/get-cookie
强经,這樣會先訪問到他的上級路徑上定義的中間件函數(shù)睡陪,app.get('/api')
,所以緊接著輸出了處理 /api 路由
匿情。
最后兰迫,進入到app.get('/api/get-cookie')
定義的應(yīng)用層中間件。首先依次執(zhí)行loginCheckSuccess()
中間件函數(shù)炬称,返回模擬登陸成功
汁果,next()
,執(zhí)行后面的中間件函數(shù)玲躯,res.json()
為服務(wù)器返回了req.cookie
中寫入的值据德。
### 通過postman分析post請求
使用postman,在請求地址欄輸入http://127.0.0.1:3000/api/get-post-deta
跷车,將返回{"errno":-1,"msg":"登陸失敗"}
其執(zhí)行原理和通過瀏覽器測試get
請求類似棘利,都是順序執(zhí)行了app.use
和app.post
的從根路徑到目標(biāo)路徑上的中間件函數(shù)。不同的是朽缴,這里我們用loginCheckFailed()
函數(shù)模擬了登錄失敗善玫,這樣由于登錄失敗,直接向postman中返回錯誤信息密强,將不再執(zhí)行后面的中間件函數(shù)蝌焚。