实现express 中间件原理

完整代码: github 仓库地址

1. 中间件原理: 核心handle方法

express_test.js 文件:

// express 中间件原理
const http = require('http')
const slice = Array.prototype.slice

class LikeExpress {
    constructor() {
        // 存放中间件的列表
        this.routes = {
            all: [],
            get: [],
            post: []
        }
    }

    register(path) {
        // 注册中间件的方法: 判断第一个参数是不是路由(字符串),
        const info = {}
        if (typeof path === 'string') {
            info.path = path
            // 从第二个参数开始转化成数组
            info.stack = slice.call(arguments, 1)
            //另一种写法 :  
            // info.stack = [...arguments].slice(1) 
        } else {
            info.path = '/'
            info.stack = [...arguments]
        }
        return info
    }

    use() {
        //  将所有参数 都传入register
        const info = this.register.apply(this, arguments)
        this.routes.all.push(info)
    }

    get() {
        const info = this.register.apply(this, arguments)
        this.routes.get.push(info)
    }

    post() {
        const info = this.register.apply(this, arguments)
        this.routes.post.push(info)
    }

    // 获取匹配的url
    match(method, url) {
        let stack = []
        if (url === '/favicon.ico') {
            return stack
        }
        let curResult = []
        curResult = curResult.concat(this.routes.all)
        curResult = curResult.concat(this.routes[method])
        curResult.forEach(item => {
            if (url.indexOf(item.path) === 0) {
                // url = '/api/get-cookie 且 item.path === '/'
                //                        且 item.path === '/api'
                //                        且 item.path === '/api/get-cookie'
                stack = stack.concat(item.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) {
        // 创建http服务 并监听
        const server = http.createServer(this.callback())
        server.listen(...args)
    }
}

// 工厂函数
module.exports = () => {
    return new LikeExpress()
}

2. 使用自行封装express

test.js文件:

//  测试自定义的express 
const express = require('./express_test')

// http请求实例
const app = express()

app.use((req, res, next) => {
    console.log("请求开始...",req.url, req.method)
    next()
})

app.use((req, res, next) => {
    // 假设在处理cookie
    console.log("处理 cookie")
    req.cookie = {
        userId: 'user233'
    }
    next()
})


app.use('/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({
        error: 0,
        data:req.cookie
    })
    next()
})

app.listen(8233, () => {
    console.log("监听 8233")
})

3. 验证

运行: node test.js
打开浏览器输入: localhost:8233/api
localhost:8233/api/get-cookie
查看控制台,感受这个流程。

发布了67 篇原创文章 · 获赞 29 · 访问量 3万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章