這是漸進式Express原始碼學習 | 小白也能懂原始碼系列文章的第六篇。
請結合該節程式碼閱讀Lesson6-獨孤求敗
目標特性和目標用法
這篇文章我們在第五篇文章的基礎上,實現一個稍微加強版的Express,功能包括
- next可以向下傳遞錯誤物件
- 錯誤捕捉
這篇文章要實現的express的期望用法如下
const express = require('../index.js')
const app = express()
app.get('/foo', function handle1 (req, res, next) {
next(new Error('Bang!'))
}, function handle2 (req, res, next) {
res.end('Will not go here')
}, function handle3 (err, req, res, next) {
console.log(`Error Caught! Error message is ${err.message}`)
next(err)
})
app.get('/foo', function (req, res, next) {
res.end('Will not go here too')
})
app.use('/foo', function (req, res, next) {
res.end('Will not go here too')
})
app.get('/foo', function (err, req, res, next) {
console.log(err.name)
res.end('Will not go here too')
})
app.use('/foo', function (err, req, res, next) {
console.log(`Error Caught! Error message is ${err.message}`)
res.end('Go here')
})
app.listen(3000)
複製程式碼
在閱讀這篇文章之前,請務必瞭解express錯誤處理,例如上面的例子中,你需要知道丟擲的錯誤是在哪個環節捕捉的,否則閱讀這個文章會吃力
原始碼及講解
這一節,會引入兩個概念,路由中介軟體和非路由中介軟體 新的章節,主要有3個變化
- lib/route/layer.js
- 增加handle_error
- lib/route/route.js
- 修改.dispatch函式
- 如果有error,呼叫layer.handle_error
- 如果沒有error,呼叫layer.handle_request
- 修改.dispatch函式
- lib/route/index.js
- 增加use函式
- 調整handle函式
首先要講解,路由中介軟體和非路由中介軟體。路由中介軟體,通過app.verb新增,結構是處理函式掛載到layer上,layer推送到route上,route的dispatch函式又掛載到一個新的layer,這個layer再推送到Router的stack中。 結構類似這樣
而對於非路由中介軟體,直接掛載到layer上,然後推送到Router的stack 結構是這樣的
所以,二者結合後,結構是這樣的
理解了上面這些,我們看具體的程式碼 首先是lib/route/layer.js
他們的區別是如果你的layer的fn是function(req, res, next) ,呼叫這個layer的handle_error會直接掉過,只有當這個layer的fn是function(err, req, res, next)才會有效
再看lib/route/route.js
注意第44行到48行,route.dispatch函式會判斷是否有error,如果有,呼叫layer的handler_error函式,這樣正常的路由就會被跳過
再看lib/route/index.js
首先是增加了一個use函式,這個函式用來增加非路由中介軟體,直接建立一個layer,繫結函式後推送到stack
最後,看Router.handle,我們聚焦在next函式
看程式碼第55行,這個地方判斷是否是路由中介軟體,如果layer有route屬性,說明是路由中介軟體,否則不是。
在process_params裡也是,如果有錯誤,呼叫layer.handle_error,否則呼叫handle_request。
本文總結及預告
本文實現了一個加強的Express。到目前為止,一個基本的Express已經實現了。和真實的Express相比,只是一些細節差異