node JS 中 express 中介軟體實現原理分析
阿新 • • 發佈:2020-12-09
技術標籤:node
一、express
express
中介軟體,如下所示:
app.use
用來註冊中介軟體,先收集起來- 遇到
http
請求,根據path
和method
判斷觸發哪些 - 實現
next
機制,即上一個通過next
觸發下一個
express
中介軟體的實現內部原理,程式碼如下所示:
const http = require('http')
const slice = Array.prototype.slice
class LikeExpress {
constructor () {
// 存放中介軟體的列表
this.routes = {
all: [], // app.use(...)
get: [], // app.get(...)
post: [] // app.post(...)
}
}
register (path) {
const info = {}
// 判斷第一個引數是否是 string 型別
if (typeof path === 'string') {
info.path = path
// 從第二個引數開始,轉換為陣列,存入 stack
info.stack = slice.call(arguments, 1)
} else {
info.path = '/'
// 從第一個引數開始,轉換為陣列,存入 stack
info.stack = slice.call(arguments, 0)
}
return info
}
use () {
const info = this.register.apply(this, arguments)
this.routes.all.push(info)
}
get () {
const info = this.register.apply(this, arguments)
this .routes.all.push(info)
}
post () {
const info = this.register.apply(this, arguments)
this.routes.all.push(info)
}
match (method, url) {
let stack = []
if (url === '/favicon.ico') {
return stack
}
// 獲取 routes
let cutRoutes = []
cutRoutes = cutRoutes.concat(this.routes.all)
cutRoutes = cutRoutes.concat(this.routes[method])
cutRoutes.forEach(routeInfo => {
if (url.indexOf(routeInfo.path) === 0) {
// url === '/api/get-cookie' 且 routeInfo.path === '/'
// url === '/api/get-cookie' 且 routeInfo.path === '/api'
// url === '/api/get-cookie' 且 routeInfo.path === '/api/get-cookie'
stack = stack.concat(routeInfo.stack)
}
})
return stack
}
// 核心的 next 機制
handle(req, res, stack) {
const next = () => {
// 拿到第一個匹配的中介軟體
const middleware = stack.shift()
if (middleware) {
// 執行中介軟體函式
middleware(req, res, next)
}
}
next()
}
callback () {
return (req, res) => {
res.json = (data) => {
res.setHeader('Content-type', 'application/json')
res.end(JSON.stringify(data))
}
const url = req.url
const method = req.method.toLowerCase()
const resultList = this.match(method, url)
this.handle(req, res, resultList)
}
}
listen (...args) {
const server = http.createServer(this.callback())
server.listen(...args)
}
}
// 工廠函式
module.exports = () => {
return new LikeExpress()
}
express
中介軟體原理的應用,程式碼如下所示:
const express = require('./like-express')
// 本次 http 請求的例項
const app = express()
app.use((req, res, next) => {
console.log('請求開始...', req.method, req.url)
next()
})
app.use((req, res, next) => {
// 假設在處理 cookie
console.log('處理 cookie...')
req.cookie = {
userId: 'abc123'
}
next()
})
app.use('/api', (req, res, next) => {
console.log('處理 /api 路由')
next()
})
app.get('/api', (req, res, next) => {
console.log('處理 /api 路由')
next()
})
app.post('/api', (req, res, next) => {
console.log('處理 /api 路由')
next()
})
// 模擬登入驗證
function loginCheck(req, res, next) {
setTimeout(() => {
console.log('模擬登入成功')
next()
})
}
app.get('/api/get-cookie', loginCheck, (req, res, next) => {
console.log('get /api/get-cookie')
res.json({
errno: 0,
data: req.cookie
})
})
app.use((req, res, next) => {
console.log('處理 404')
res.json({
errno: -1,
msg: '404 not found'
})
})
app.listen(8000, () => {
console.log('server is running on port 8000')
})