欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

NodeJs?Express中間件超詳細(xì)講解

 更新時(shí)間:2022年08月24日 16:10:09   作者:薇z  
Express中間件本質(zhì)上就是一個(gè)function處理函數(shù),多個(gè)中間件之間,共享同一份req和res,我們就可以在上游的中間件中統(tǒng)一為req或者res對(duì)象添加自定義的屬性或方法,供下游的中間件或路由進(jìn)行使用,非常方便

什么是中間件

中間件(Middleware ),特指業(yè)務(wù)流程的中間處理環(huán)節(jié)

現(xiàn)實(shí)生活中的例子

在處理污水的時(shí)候,一般都要經(jīng)過(guò)三個(gè)處理環(huán)節(jié),從而保證處理過(guò)后的廢水,達(dá)到排放標(biāo)準(zhǔn)

處理污水的這三個(gè)中間處理環(huán)節(jié),就可以叫做中間件。

Express 中間件的調(diào)用流程

當(dāng)一個(gè)請(qǐng)求到達(dá) Express 的服務(wù)器之后,可以連續(xù)調(diào)用多個(gè)中間件,從而對(duì)這次請(qǐng)求進(jìn)行預(yù)處理。

Express 中間件的格式

Express 的中間件,本質(zhì)上就是一個(gè) function 處理函數(shù),Express 中間件的格式如下:

注意:中間件函數(shù)的形參列表中,必須包含 next 參數(shù)。而路由處理函數(shù)中只包含 req 和 res。

next 函數(shù)的作用

next 函數(shù)是實(shí)現(xiàn)多個(gè)中間件連續(xù)調(diào)用的關(guān)鍵,它表示把流轉(zhuǎn)關(guān)系轉(zhuǎn)交給下一個(gè)中間件或路由。

定義中間件函數(shù)

可以通過(guò)如下的方式,定義一個(gè)最簡(jiǎn)單的中間件函數(shù):

全局生效的中間件

客戶端發(fā)起的任何請(qǐng)求,到達(dá)服務(wù)器之后,都會(huì)觸發(fā)的中間件,叫做全局生效的中間件。

通過(guò)調(diào)用 app.use(中間件函數(shù)),即可定義一個(gè)全局生效的中間件,示例代碼如下:

定義全局中間件的簡(jiǎn)化形式

const express = require('express')
const app = express()
// // 定義一個(gè)最簡(jiǎn)單的中間件函數(shù)
// const mw = function (req, res, next) {
//   console.log('這是最簡(jiǎn)單的中間件函數(shù)')
//   // 把流轉(zhuǎn)關(guān)系,轉(zhuǎn)交給下一個(gè)中間件或路由
//   next()
// }
// // 將 mw 注冊(cè)為全局生效的中間件
// app.use(mw)
// 這是定義全局中間件的簡(jiǎn)化形式
app.use((req, res, next) => {
  console.log('這是最簡(jiǎn)單的中間件函數(shù)')
  next()
})
app.get('/', (req, res) => {
  console.log('調(diào)用了 / 這個(gè)路由')
  res.send('Home page.')
})
app.get('/user', (req, res) => {
  console.log('調(diào)用了 /user 這個(gè)路由')
  res.send('User page.')
})
app.listen(80, () => {
  console.log('http://127.0.0.1')
})

當(dāng)在apifox請(qǐng)求這兩個(gè)請(qǐng)求時(shí),都會(huì)先調(diào)用這個(gè)中間件再返回請(qǐng)求的內(nèi)容。

中間件的作用

多個(gè)中間件之間,共享同一份 req 和 res?;谶@樣的特性,我們可以在上游的中間件中,統(tǒng)一為 req 或 res 對(duì)象添加自定義的屬性或方法,供下游的中間件或路由進(jìn)行使用。

const express = require('express')
const app = express()
// 這是定義全局中間件的簡(jiǎn)化形式
app.use((req, res, next) => {
  // 獲取到請(qǐng)求到達(dá)服務(wù)器的時(shí)間
  const time = Date.now()
  // 為 req 對(duì)象,掛載自定義屬性,從而把時(shí)間共享給后面的所有路由
  req.startTime = time
  next()
})
app.get('/', (req, res) => {
  res.send('Home page.' + req.startTime)
})
app.get('/user', (req, res) => {
  res.send('User page.' + req.startTime)
})
app.listen(80, () => {
  console.log('http://127.0.0.1')
})

定義多個(gè)全局中間件

可以使用 app.use() 連續(xù)定義多個(gè)全局中間件??蛻舳苏?qǐng)求到達(dá)服務(wù)器之后,會(huì)按照中間件定義的先后順序依次進(jìn)行調(diào)用,示例代碼如下:

const express = require('express')
const app = express()
// 定義第一個(gè)全局中間件
app.use((req, res, next) => {
  console.log('調(diào)用了第1個(gè)全局中間件')
  next()
})
// 定義第二個(gè)全局中間件
app.use((req, res, next) => {
  console.log('調(diào)用了第2個(gè)全局中間件')
  next()
})
// 定義一個(gè)路由
app.get('/user', (req, res) => {
  res.send('User page.')
})
app.listen(80, () => {
  console.log('http://127.0.0.1')
})

局部生效的中間件

不使用 app.use() 定義的中間件,叫做局部生效的中間件,示例代碼如下:

// 導(dǎo)入 express 模塊
const express = require('express')
// 創(chuàng)建 express 的服務(wù)器實(shí)例
const app = express()
// 1. 定義中間件函數(shù)
const mw1 = (req, res, next) => {
  console.log('調(diào)用了局部生效的中間件')
  next()
}
// 2. 創(chuàng)建路由,mw1只在當(dāng)前路由生效
app.get('/', mw1, (req, res) => {
  res.send('Home page.')
})
app.get('/user', (req, res) => {
  res.send('User page.')
})
// 調(diào)用 app.listen 方法,指定端口號(hào)并啟動(dòng)web服務(wù)器
app.listen(80, function () {
  console.log('Express server running at http://127.0.0.1')
})

定義多個(gè)局部中間件

可以在路由中,通過(guò)如下兩種等價(jià)的方式,使用多個(gè)局部中間件:

// 導(dǎo)入 express 模塊
const express = require('express')
// 創(chuàng)建 express 的服務(wù)器實(shí)例
const app = express()
// 1. 定義中間件函數(shù)
const mw1 = (req, res, next) => {
  console.log('調(diào)用了第一個(gè)局部生效的中間件')
  next()
}
const mw2 = (req, res, next) => {
  console.log('調(diào)用了第二個(gè)局部生效的中間件')
  next()
}
// 2. 創(chuàng)建路由
app.get('/', [mw1, mw2], (req, res) => {
  res.send('Home page.')
})
app.get('/user', (req, res) => {
  res.send('User page.')
})
// 調(diào)用 app.listen 方法,指定端口號(hào)并啟動(dòng)web服務(wù)器
app.listen(80, function () {
  console.log('Express server running at http://127.0.0.1')
})

了解中間件的5個(gè)使用注意事項(xiàng)

① 一定要在路由之前注冊(cè)中間件

② 客戶端發(fā)送過(guò)來(lái)的請(qǐng)求,可以連續(xù)調(diào)用多個(gè)中間件進(jìn)行處理

③ 執(zhí)行完中間件的業(yè)務(wù)代碼之后,不要忘記調(diào)用 next() 函數(shù)

④ 為了防止代碼邏輯混亂,調(diào)用 next() 函數(shù)后不要再寫額外的代碼

⑤ 連續(xù)調(diào)用多個(gè)中間件時(shí),多個(gè)中間件之間,共享 req 和 res 對(duì)象

中間件的分類

為了方便大家理解和記憶中間件的使用,Express 官方把常見的中間件用法,分成了 5 大類,分別是:

① 應(yīng)用級(jí)別的中間件

② 路由級(jí)別的中間件

③ 錯(cuò)誤級(jí)別的中間件

④ Express 內(nèi)置的中間件

⑤ 第三方的中間件

應(yīng)用級(jí)別的中間件

通過(guò) app.use() 或 app.get() 或 app.post() ,綁定到 app 實(shí)例上的中間件,叫做應(yīng)用級(jí)別的中間件,代碼示例如下:

路由級(jí)別的中間件

綁定到 express.Router() 實(shí)例上的中間件,叫做路由級(jí)別的中間件。它的用法和應(yīng)用級(jí)別中間件沒(méi)有任何區(qū)別。只不過(guò),應(yīng)用級(jí)別中間件是綁定到 app 實(shí)例上,路由級(jí)別中間件綁定到 router 實(shí)例上,代碼示例如下:

錯(cuò)誤級(jí)別的中間件

錯(cuò)誤級(jí)別中間件的作用:專門用來(lái)捕獲整個(gè)項(xiàng)目中發(fā)生的異常錯(cuò)誤,從而防止項(xiàng)目異常崩潰的問(wèn)題。

格式:錯(cuò)誤級(jí)別中間件的 function 處理函數(shù)中,必須有 4 個(gè)形參,形參順序從前到后,分別是 (err, req, res, next)。

注意:錯(cuò)誤級(jí)別的中間件,必須注冊(cè)在所有路由之后!

// 導(dǎo)入 express 模塊
const express = require('express')
// 創(chuàng)建 express 的服務(wù)器實(shí)例
const app = express()
// 1. 定義路由
app.get('/', (req, res) => {
  // 1.1 人為的制造錯(cuò)誤
  throw new Error('服務(wù)器內(nèi)部發(fā)生了錯(cuò)誤!')
  res.send('Home page.')
})
// 2. 定義錯(cuò)誤級(jí)別的中間件,捕獲整個(gè)項(xiàng)目的異常錯(cuò)誤,從而防止程序的崩潰
app.use((err, req, res, next) => {
  console.log('發(fā)生了錯(cuò)誤!' + err.message)
  res.send('Error:' + err.message)
})
// 調(diào)用 app.listen 方法,指定端口號(hào)并啟動(dòng)web服務(wù)器
app.listen(80, function () {
  console.log('Express server running at http://127.0.0.1')
})

Express內(nèi)置的中間件

自 Express 4.16.0 版本開始,Express 內(nèi)置了 3 個(gè)常用的中間件,極大的提高了 Express 項(xiàng)目的開發(fā)效率和體驗(yàn):

① express.static 快速托管靜態(tài)資源的內(nèi)置中間件,例如: HTML 文件、圖片、CSS 樣式等(無(wú)兼容性)

② express.json 解析 JSON 格式的請(qǐng)求體數(shù)據(jù)(有兼容性,僅在 4.16.0+ 版本中可用)

③ express.urlencoded 解析 URL-encoded 格式的請(qǐng)求體數(shù)據(jù)(有兼容性,僅在 4.16.0+ 版本中可用)

// 導(dǎo)入 express 模塊
const express = require('express')
// 創(chuàng)建 express 的服務(wù)器實(shí)例
const app = express()
// 注意:除了錯(cuò)誤級(jí)別的中間件,其他的中間件,必須在路由之前進(jìn)行配置
// 通過(guò) express.json() 這個(gè)中間件,解析表單中的 JSON 格式的數(shù)據(jù)
app.use(express.json())
// 通過(guò) express.urlencoded() 這個(gè)中間件,來(lái)解析 表單中的 url-encoded 格式的數(shù)據(jù)
app.use(express.urlencoded({ extended: false }))
app.post('/user', (req, res) => {
  // 在服務(wù)器,可以使用 req.body 這個(gè)屬性,來(lái)接收客戶端發(fā)送過(guò)來(lái)的請(qǐng)求體數(shù)據(jù)
  // 默認(rèn)情況下,如果不配置解析表單數(shù)據(jù)的中間件,則 req.body 默認(rèn)等于 undefined
  console.log(req.body)
  res.send('ok')
})
app.post('/book', (req, res) => {
  // 在服務(wù)器端,可以通過(guò) req,body 來(lái)獲取 JSON 格式的表單數(shù)據(jù)和 url-encoded 格式的數(shù)據(jù)
  console.log(req.body)
  res.send('ok')
})
// 調(diào)用 app.listen 方法,指定端口號(hào)并啟動(dòng)web服務(wù)器
app.listen(80, function () {
  console.log('Express server running at http://127.0.0.1')
})

第三方的中間件

非 Express 官方內(nèi)置的,而是由第三方開發(fā)出來(lái)的中間件,叫做第三方中間件。在項(xiàng)目中,大家可以按需下載并配置

第三方中間件,從而提高項(xiàng)目的開發(fā)效率。

例如:在 express@4.16.0 之前的版本中,經(jīng)常使用 body-parser 這個(gè)第三方中間件,來(lái)解析請(qǐng)求體數(shù)據(jù)。使用步

驟如下:

① 運(yùn)行 npm install body-parser 安裝中間件

② 使用 require 導(dǎo)入中間件

③ 調(diào)用 app.use() 注冊(cè)并使用中間件

注意:Express 內(nèi)置的 express.urlencoded 中間件,就是基于 body-parser 這個(gè)第三方中間件進(jìn)一步封裝出來(lái)的。

// 導(dǎo)入 express 模塊
const express = require('express')
// 創(chuàng)建 express 的服務(wù)器實(shí)例
const app = express()
// 1. 導(dǎo)入解析表單數(shù)據(jù)的中間件 body-parser
const parser = require('body-parser')
// 2. 使用 app.use() 注冊(cè)中間件
app.use(parser.urlencoded({ extended: false }))
// app.use(express.urlencoded({ extended: false }))
app.post('/user', (req, res) => {
  // 如果沒(méi)有配置任何解析表單數(shù)據(jù)的中間件,則 req.body 默認(rèn)等于 undefined
  console.log(req.body)
  res.send('ok')
})
// 調(diào)用 app.listen 方法,指定端口號(hào)并啟動(dòng)web服務(wù)器
app.listen(80, function () {
  console.log('Express server running at http://127.0.0.1')
})

自定義中間件

1. 需求描述與實(shí)現(xiàn)步驟

自己手動(dòng)模擬一個(gè)類似于 express.urlencoded 這樣的中間件,來(lái)解析 POST 提交到服務(wù)器的表單數(shù)據(jù)。

實(shí)現(xiàn)步驟:

① 定義中間件

② 監(jiān)聽 req 的 data 事件

③ 監(jiān)聽 req 的 end 事件

④ 使用 querystring 模塊解析請(qǐng)求體數(shù)據(jù)

⑤ 將解析出來(lái)的數(shù)據(jù)對(duì)象掛載為 req.body

⑥ 將自定義中間件封裝為模塊

2. 定義中間件

使用 app.use() 來(lái)定義全局生效的中間件,代碼如下:

3 .監(jiān)聽req的data事件

在中間件中,需要監(jiān)聽 req 對(duì)象的 data 事件,來(lái)獲取客戶端發(fā)送到服務(wù)器的數(shù)據(jù)。

如果數(shù)據(jù)量比較大,無(wú)法一次性發(fā)送完畢,則客戶端會(huì)把數(shù)據(jù)切割后,分批發(fā)送到服務(wù)器。所以 data 事件可能會(huì)觸發(fā)多次,每一次觸發(fā) data 事件時(shí),獲取到數(shù)據(jù)只是完整數(shù)據(jù)的一部分,需要手動(dòng)對(duì)接收到的數(shù)據(jù)進(jìn)行拼接。

4. 監(jiān)聽req的end事件

當(dāng)請(qǐng)求體數(shù)據(jù)接收完畢之后,會(huì)自動(dòng)觸發(fā) req 的 end 事件。

因此,我們可以在 req 的 end 事件中,拿到并處理完整的請(qǐng)求體數(shù)據(jù)。示例代碼如下:

5. 使用Qs模塊解析請(qǐng)求體數(shù)據(jù)

Node.js 內(nèi)置了一個(gè)Qs 模塊,專門用來(lái)處理查詢字符串。通過(guò)這個(gè)模塊提供的 parse() 函數(shù),可以輕松把查詢字符串,解析成對(duì)象的格式。示例代碼如下:

6. 將解析出來(lái)的數(shù)據(jù)對(duì)象掛載為req.body

上游的中間件和下游的中間件及路由之間,共享同一份 req 和 res。因此,我們可以將解析出來(lái)的數(shù)據(jù),掛載為 req 的自定義屬性,命名為 req.body,供下游使用。示例代碼如下:

7. 將自定義中間件封裝為模塊

為了優(yōu)化代碼的結(jié)構(gòu),我們可以把自定義的中間件函數(shù),封裝為獨(dú)立的模塊,示例代碼如下:

// 導(dǎo)入 express 模塊
const express = require('express')
// 創(chuàng)建 express 的服務(wù)器實(shí)例
const app = express()
// 導(dǎo)入 Node.js 內(nèi)置的 Qs 模塊
const qs = require('Qs')
// 這是解析表單數(shù)據(jù)的中間件
app.use((req, res, next) => {
  // 定義中間件具體的業(yè)務(wù)邏輯
  // 1. 定義一個(gè) str 字符串,專門用來(lái)存儲(chǔ)客戶端發(fā)送過(guò)來(lái)的請(qǐng)求體數(shù)據(jù)
  let str = ''
  // 2. 監(jiān)聽 req 的 data 事件
  req.on('data', (chunk) => {
    str += chunk
  })
  // 3. 監(jiān)聽 req 的 end 事件
  req.on('end', () => {
    // 在 str 中存放的是完整的請(qǐng)求體數(shù)據(jù)
    // console.log(str)
    // TODO: 把字符串格式的請(qǐng)求體數(shù)據(jù),解析成對(duì)象格式
    const body = qs.parse(str)
    req.body = body
    next()
  })
})
app.post('/user', (req, res) => {
  res.send(req.body)
})
// 調(diào)用 app.listen 方法,指定端口號(hào)并啟動(dòng)web服務(wù)器
app.listen(80, function () {
  console.log('Express server running at http://127.0.0.1')
})

封裝自定義中間件

// 導(dǎo)入 Node.js 內(nèi)置的 Qs 模塊
const qs = require('Qs')
const bodyParser = (req, res, next) => {
  // 定義中間件具體的業(yè)務(wù)邏輯
  // 1. 定義一個(gè) str 字符串,專門用來(lái)存儲(chǔ)客戶端發(fā)送過(guò)來(lái)的請(qǐng)求體數(shù)據(jù)
  let str = ''
  // 2. 監(jiān)聽 req 的 data 事件
  req.on('data', (chunk) => {
    str += chunk
  })
  // 3. 監(jiān)聽 req 的 end 事件
  req.on('end', () => {
    // 在 str 中存放的是完整的請(qǐng)求體數(shù)據(jù)
    // console.log(str)
    // TODO: 把字符串格式的請(qǐng)求體數(shù)據(jù),解析成對(duì)象格式
    const body = qs.parse(str)
    req.body = body
    next()
  })
}
module.exports = bodyParser
// 導(dǎo)入 express 模塊
const express = require('express')
// 創(chuàng)建 express 的服務(wù)器實(shí)例
const app = express()
// 1. 導(dǎo)入自己封裝的中間件模塊
const customBodyParser = require('./14.custom-body-parser')
// 2. 將自定義的中間件函數(shù),注冊(cè)為全局可用的中間件
app.use(customBodyParser)
app.post('/user', (req, res) => {
  res.send(req.body)
})
// 調(diào)用 app.listen 方法,指定端口號(hào)并啟動(dòng)web服務(wù)器
app.listen(80, function () {
  console.log('Express server running at http://127.0.0.1')
})

到此這篇關(guān)于NodeJs Express中間件超詳細(xì)講解的文章就介紹到這了,更多相關(guān)NodeJs Express中間件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 前端node Session和JWT鑒權(quán)登錄示例詳解

    前端node Session和JWT鑒權(quán)登錄示例詳解

    關(guān)于前端鑒權(quán)登錄是比較常見的需求了,本文將從服務(wù)端渲染和前后端分離的不同角度下演示鑒權(quán),為大家介紹前端node Session和JWT鑒權(quán)登錄示例詳解
    2022-07-07
  • 詳解如何使用Node.js連接數(shù)據(jù)庫(kù)ORM

    詳解如何使用Node.js連接數(shù)據(jù)庫(kù)ORM

    這篇文章主要為大家介紹了詳解如何使用Node.js連接數(shù)據(jù)庫(kù)ORM示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • 解析Node.js異常處理中domain模塊的使用方法

    解析Node.js異常處理中domain模塊的使用方法

    這篇文章主要介紹了Node.js異常處理中domain模塊的使用方法,文中最后提到了內(nèi)存泄漏的相關(guān)問(wèn)題,值得注意,需要的朋友可以參考下
    2016-02-02
  • node 標(biāo)準(zhǔn)輸入流和輸出流代碼實(shí)例

    node 標(biāo)準(zhǔn)輸入流和輸出流代碼實(shí)例

    這篇文章主要介紹了node 標(biāo)準(zhǔn)輸入流和輸出流代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-09-09
  • node基于async/await對(duì)mysql進(jìn)行封裝

    node基于async/await對(duì)mysql進(jìn)行封裝

    這篇文章主要介紹了node基于async/await對(duì)mysql進(jìn)行封裝,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,,需要的朋友可以參考下
    2019-06-06
  • 基于docker搭建node環(huán)境開發(fā)服務(wù)器全過(guò)程

    基于docker搭建node環(huán)境開發(fā)服務(wù)器全過(guò)程

    這篇文章主要給大家介紹了關(guān)于如何基于docker搭建node環(huán)境開發(fā)服務(wù)器的相關(guān)資料,本文將采用docker技術(shù)部署一個(gè)簡(jiǎn)單的nodejs應(yīng)用,文中通過(guò)圖文以及代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-11-11
  • node.js利用socket.io實(shí)現(xiàn)多人在線匹配聯(lián)機(jī)五子棋

    node.js利用socket.io實(shí)現(xiàn)多人在線匹配聯(lián)機(jī)五子棋

    這篇文章主要介紹了node.js利用socket.io實(shí)現(xiàn)多人在線匹配聯(lián)機(jī)五子棋的操作方法,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2018-05-05
  • pnpm管理依賴包如何節(jié)省磁盤空間詳解

    pnpm管理依賴包如何節(jié)省磁盤空間詳解

    這篇文章主要為大家介紹了pnpm管理依賴包如何節(jié)省磁盤空間詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • node.js 使用 net 模塊模擬 websocket 握手進(jìn)行數(shù)據(jù)傳遞操作示例

    node.js 使用 net 模塊模擬 websocket 握手進(jìn)行數(shù)據(jù)傳遞操作示例

    這篇文章主要介紹了node.js 使用 net 模塊模擬 websocket 握手進(jìn)行數(shù)據(jù)傳遞操作,結(jié)合實(shí)例形式分析了node.js基于net模塊模擬 websocket握手相關(guān)原理及進(jìn)行數(shù)據(jù)傳遞具體操作技巧,需要的朋友可以參考下
    2020-02-02
  • 史上無(wú)敵詳細(xì)的Node.Js環(huán)境搭建步驟記錄

    史上無(wú)敵詳細(xì)的Node.Js環(huán)境搭建步驟記錄

    Node.js是一個(gè)事件驅(qū)動(dòng)I/O服務(wù)端JavaScript環(huán)境,由于其擁有異步非阻塞、環(huán)境搭建簡(jiǎn)單、實(shí)踐應(yīng)用快等特性,使得其在新一代編程開發(fā)中更為流行,下面這篇文章主要給大家介紹了關(guān)于Node.Js環(huán)境搭建步驟記錄的相關(guān)資料,需要的朋友可以參考下
    2023-03-03

最新評(píng)論