NodeJs Express中間件使用流程解析
中間件(Middleware),特指業(yè)務流程的中間處理環(huán)節(jié)
1、調用流程
當一個請求到達Express的服務器之后,可以連續(xù)調用多個中間件,從而對這次請求進行預處理。
2、格式
Express的中間件,本質上就是一個function處理函數(shù)
,Express中間件的格式如下:
app.get('/',(req,res,next) => { next() })
中間件的形參列表中,必須包含next
參數(shù),而路由處理函數(shù)只包含 req 和 res
3、next函數(shù)的作用
next函數(shù)是實現(xiàn)多個中間件連續(xù)調用的關鍵,它表示把流轉關系轉交給下一個中間件或路由
4、定義中間件函數(shù)
const vm = function(req,res,next) { console.log('這是最簡單的中間件函數(shù)'); // 把流轉關系轉交給下一個中間件或路由 next() }
5、全局生效的中間件
客戶端發(fā)起的任何請求,到達服務器之后,都會觸發(fā)的中間件
通過app.use(中間件函數(shù)),即可定義一個全局生效的中間件
const vm = function(req,res,next) { console.log('這是最簡單的中間件函數(shù)'); // 把流轉關系轉交給下一個中間件或路由 next() } app.use(vm)
6、中間件的作用
多個中間件之間共享一份req
和 res
。可以在上游的中間件中,統(tǒng)一為 req 或 res 對象添加自定義的屬性或方法,供下游的中間件或路由進行使用。
7、定義多個全局中間件
可以使用app.use()
連續(xù)定義多個全局中間件。客戶請求到達服務器之后,會按照中間件定義的先后順序依次進行調用
app.use(function(req,res,next) { console.log('調用了第一個中間件'); next() }) app.use(function(req,res,next) { console.log('調用了第二個中間件'); next() }) app.get('/',(req,res) => { res.send('OK.') })
當請求http://127.0.0.1/
時
8、局部生效的中間件
不使用 app.use()
定義的中間件為局部生效的中間件
const vm = function(req,res,next) { console.log('調用了局部生效的中間件'); next() } app.get('/',vm,(req,res) => { res.send('Home Page.') }) app.get('/user',vm,(req,res) => { res.send('User Page.') })
vm中間件只會在/
路由中生效,不會影響其他的路由。當請求http://127.0.0.1/
時控制臺有打印,請求http://127.0.0.1/user
時,控制臺沒有打印。
9、定義多個局部中間件
app.get('/',mw1,mw2,(req,res) => {}) app.get('/',[mw1,mw2],(req,res) => {})
如上兩種寫法是等價的
10、了解中間件的注意事項
① 一定要在路由之前注冊中間件
② 客戶端發(fā)過來的請求,可以連續(xù)調用多個中間件進行處理
③ 執(zhí)行完中間件的業(yè)務代碼之后,要調用 next() 函數(shù)
④ 為了防止代碼邏輯混亂,調用 next() 函數(shù)后不要再寫額外的代碼
⑤ 連續(xù)調用多個中間件時,多個中間件之間共享 req 和 res 對象
11、中間件的分類
1、應用級別的中間件
通過 app.use() 或 app.get() 或 app.post(),綁定到 app
實例上的中間件
2、路由級別的中間件
綁定到 express.Router()
路由實例上的中間件
var app = express() var router = express.Router() router.use(function(req,res,next) {})
3、錯誤級別的中間件
專門用來捕獲整個項目中發(fā)生的異常信息,從而防止項目異常崩潰的問題
格式:function處理函數(shù)中,必須有4個形參,從前到后分別是(err
、req、res、next)
app.get('/',(req,res) => { throw new Error('服務器內部發(fā)生了錯誤!') res.send('Home Page.') })
此時通過http://127.0.0.1/
訪問服務器,服務器就發(fā)生了崩潰
// 定義錯誤級別的中間件捕獲整個項目的異常錯誤,從而防止程序的崩潰 app.use((err,req,res,next) => { res.send('Error:' + err.message) })
此時通過http://127.0.0.1/
訪問服務器,服務器雖然發(fā)生了錯誤,但是沒有崩潰
注意:錯誤級別的中間件必須注冊在所有路由之后
4、Express內置的中間件
自 Express 4.16.0 版本開始,Express內置了3個常用的中間件,極大的提高了Express項目的開發(fā)效率和體驗
① express.static
快速托管靜態(tài)資源的內置中間件,例如:HTML文件、圖片、CSS樣式等(無兼容性)
② express.json
解析 JSON 格式的請求體數(shù)據(jù)(有兼容性,僅在 4.16.0+版本中可用)
app.post('/user',(req,res) => { // 通過 req.body 來接收客戶端發(fā)送過來的請求體數(shù)據(jù) console.log(req.body) res.send('ok') })
訪問 http://127.0.0.1/user
,并使用post請求發(fā)送JSON
格式的參數(shù),如 {"name":"zs","age":18}
如上打印 req.body
值為 undefined
app.use(express.json()) app.post('/user',(req,res) => { console.log(req.body) res.send('ok') })
配置了解析JSON格式的請求體數(shù)據(jù)的中間件,打印 req.body
值為 {name:'zs',age:'18'}
③ express.urlencoded
解析 URL-encoded 格式的請求體數(shù)據(jù)(有兼容性,僅在 4.16.0+版本中可用)
app.post('/user',(req,res) => { console.log(req.body) res.send('ok') })
訪問 http://127.0.0.1/user
,并使用post請求發(fā)送x-www-form-urlencoded
格式的參數(shù),如 key:name,value:zs
、key:age,value:18
,如上打印 req.body
值為 undefined
app.use(express.json()) app.post('/user',(req,res) => { console.log(req.body) res.send('ok') })
配置的是解析JSON格式的請求體數(shù)據(jù)的中間件,打印 req.body
值為 {}
app.use(express.urlencoded({extended:false})) app.post('/user',(req,res) => { console.log(req.body) res.send('ok') })
配置了解析表單中 urlencoded 格式的請求體數(shù)據(jù)的中間件,打印 req.body
值為 {name:'zs',age:'18'}
5、第三方中間件
非 Express 官方內置的,而是由第三方開發(fā)出來的中間件為第三方中間件??梢园葱柘螺d并配置,從而提高項目的開發(fā)效率
如 body-parser
這個第三方中間件用來解析請求體數(shù)據(jù)
① 運行 npm i body-parser
② 使用 require
導入中間件
③ 調用app.use()
注冊并使用中間件
const parser = require('body-parser') app.use(parser.urlencoded({extended:false}))
注意:Express內置的express.urlencoded
中間件,就是基于body-parser
這個第三方中間件進一步封裝出來的
6、自定義中間件
手動模擬一個類似于 express.urlencoded 的中間件,來解析POST提交到服務器的表單數(shù)據(jù)
① 定義中間件
② 監(jiān)聽 req 的 data 事件
③ 監(jiān)聽 req 的 end 事件
④ 使用 querystring 模塊解析請求體數(shù)據(jù)
⑤ 將解析出來的數(shù)據(jù)對象掛載為 req.body
⑥ 將自定義中間件封裝為模塊
1、定義中間件
app.use((req,res,next) => {<!--{cke_protected}{C}%3C!%2D%2D%20%2D%2D%3E-->})
2、監(jiān)聽 req 的 data 事件
監(jiān)聽 req 對象的 data 事件來獲取客戶端發(fā)送到服務器的數(shù)據(jù)。
如果數(shù)據(jù)量比較大無法一次性發(fā)送完畢,則客戶端會把數(shù)據(jù)切割后分批發(fā)送到服務器,每次觸發(fā) data 事件獲取到的數(shù)據(jù)只是完整數(shù)據(jù)的一部分,需要手動對接收的數(shù)據(jù)進行拼接
app.use((req,res,next) => { // 1. 定義一個變量,專門用來存儲客戶端發(fā)送過來的請求體數(shù)據(jù) let str = '' // 2. 監(jiān)聽req的data事件 req.on('data',(chunk) => { str += chunk }) })
3、監(jiān)聽 req 的 end 事件
當請求體數(shù)據(jù)接收完畢之后,會自動觸發(fā) req 的 end 事件
app.use((req,res,next) => { let str = '' req.on('data',(chunk) => { str += chunk }) // 3.監(jiān)聽req的end事件 req.on('end',() => { // 在str中存放的是完整的請求體數(shù)據(jù) console.log(str); }) })
得到的值為:name=zs&age=18&gender=%E7%94%B7
4、使用 querystring 模塊解析請求體數(shù)據(jù)
Node.js 內置了一個 querystring
模塊,專門用來處理查詢字符串。通過這個模塊提供的 parse()
函數(shù),可以把查詢字符串解析成對象的格式
const qs = require('querystring') app.use((req,res,next) => { let str = '' req.on('data',(chunk) => { str += chunk }) req.on('end',() => { // 4.把字符串格式的請求體數(shù)據(jù)解析成對象格式 const body = qs.parse(str) console.log(body) }) })
得到的值為:{ name: 'zs', age: '18', gender: '男' }
5、將解析出來的數(shù)據(jù)對象掛載為 req.body
上游的中間件和下游的中間件及路由之間共享同一份 req
和 res
。因此可以將解析出來的數(shù)據(jù)掛載為 req 的自定義屬性,命名為 req.body 供下游使用
const qs = require('querystring') app.use((req,res,next) => { let str = '' req.on('data',(chunk) => { str += chunk }) req.on('end',() => { const body = qs.parse(str) // 5. 將解析出來的請求體對象掛載為 req.body 屬性,最后要調用 next() 函數(shù)執(zhí)行后續(xù)的業(yè)務邏輯 req.body = body next() }) })
6、將自定義中間件封裝為模塊
把自定義的中間件函數(shù)封裝為獨立的模塊 custom-body-parser.js
const qs = require('querystring') const bodyParser = function(req,res,next) { let str = '' req.on('data',(chunk) => { str += chunk }) req.on('end',() => { const body = qs.parse(str) req.body = body next() }) } module.exports = bodyParser
使用:
// 導入自己封裝的中間件模塊 const customBodyParser = require('./custom-body-parser') // 將自定義的中間件函數(shù)注冊為全局可用的中間件 app.use(customBodyParser)
到此這篇關于NodeJs Express中間件使用流程解析的文章就介紹到這了,更多相關NodeJs Express中間件內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
如何讓Nodejs支持H5 History模式(connect-history-api-fallback源碼分析)
這篇文章主要介紹了如何讓Nodejs支持H5 History模式(connect-history-api-fallback源碼分析),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-05-05Node.JS更改Windows注冊表Regedit的方法小結
注冊表是windows操作系統(tǒng)中的一個核心數(shù)據(jù)庫,這里介紹一些通過node.js操作注冊表的幾種方法,感興趣的朋友參考下吧2017-08-08nodejs配置express服務器運行自動打開瀏覽器詳細步驟
在nodejs中使用express來搭建框架可以說是非常的簡單方便,下面這篇文章主要給大家介紹了關于nodejs配置express服務器運行自動打開瀏覽器的相關資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下2024-01-01