上一篇理解Express的使用之后, 再总结一篇Express中间件的简单实现原理。
我们知道Express中间件就是一个个的函数, 那么怎么让这些函数有序的执行呢? 那就需要我们调用 next
函数。其实 next
函数调用的就是下一个中间件函数。
以下代码实现了简单的 app.use
注册中间件, 以及 get
、post
方式的中间件。其他请求方式的中间件实现同理
核心代码:
const next = () => {
const stack = stacks.shift()
if(stack) {
stack(req, res, next)
}
}
next()
stacks就是一个数组队列, 存放所有符合规则的中间件函数。遵循先进先出
的原则。也就是最先注册的中间件函数最先执行。
实现代码
const http = require('http')
const slice = Array.prototype.slice
class Express {
constructor() {
this.router = {
all: [], // 匹配所有额中间件函数
get: [],
post: []
}
}
/**
* 这里整合中间件
* @param {string} path
* @returns {object}
*/
middlewareHandler(path) {
const info = {}
if (typeof path === 'string') {
info.path = path
info.stack = slice.call(arguments, 1) // 中间件数组
} else {
info.path = '/'
info.stack = slice.call(arguments, 0)
}
return info
}
use() {
const allStack = this.middlewareHandler(...arguments)
this.router.all.push(allStack)
}
get() {
const getStack = this.middlewareHandler(...arguments)
this.router.get.push(getStack)
}
post() {
const postStack = this.middlewareHandler(...arguments)
this.router.post.push(postStack)
}
/**
*
* @param {string} method
* @param {string} url
* @returns {Array}
*/
accordStack(method, url) {
let stacks = []
stacks = stacks.concat(this.router.all)
stacks = stacks.concat(this.router[method])
return stacks
.filter(stack => {
return url.indexOf(stack.path) !== -1
}).map(item => item.stack[0])
}
handler(req, res, stacks) {
// 函数表达式
const next = () => {
const stack = stacks.shift()
if(stack) {
stack(req, res, next)
}
}
next()
}
callback() {
return (req, res) => {
res.json = data => {
res.setHeader('Content-Type', 'application/json')
res.end(JSON.stringify(data))
}
// 拿到请求的方法和url, 对中间件函数进行筛选
const {method, url} = req
const stacks = this.accordStack(method.toLowerCase(), url)
this.handler(req, res, stacks)
}
}
listen(...args) {
const server = http.createServer(this.callback())
server.listen(...args)
}
}
// 工厂模式, 导出一个实例对象
module.exports = () => {
return new Express()
}