百来行代码简洁解析express中间件原理(并测试)

本文深入剖析自造的Express框架,展示如何通过类构造中间件系统,实现HTTP请求的处理和响应。通过具体代码示例,讲解了中间件注册、路由匹配及请求处理的核心机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

下面代码有详细注释

文件like-express.js

const http =require('http')
//
const slice =Array.prototype.slice

class LikeExpress{
    constructor(){
        // 存放中间件的列表
        this.routes ={  
            all:[], // app.use(...)
            get:[], // app.get()
            post:[] // app.post
            // 还有其他方法比如put,patch等
            
        }
    }
    
	//用register存储获得info存储中间件,下面的use(),get(),post()会分别继承方法将不同的中间件存入
	//上面的routes的不同数组中
    register(path){
        const info = {} //当前的注册信息
        if(typeof path === 'string'){//qpp.use第一个参数没有的话就是命中了根路由
            info.path = path
            info.stack =slice.call(arguments,1)//取出第二个参数放在数组里面

        }else{
            info.path = '/'
            info.stack =slice.call(arguments,0)
        }
        return info
    }
	
    use(){
        const info =this.register.apply(this,arguments) //把当前函数所有的参数都放在register中并返回info
        // 推入routes.all中
        this.routes.all.push(info)
    }

    get(){
        const info =this.register.apply(this,arguments) //把当前函数所有的参数都放在register中并返回info
        // 推入route. get中
        this.routes.get.push(info)
    }

    post(){
        const info =this.register.apply(this,arguments) //把当前函数所有的参数都放在register中并返回info
        
        this.routes.post.push(info)
    }
//----------------------------------------------------------------

//macth主要用于匹配get,post等方法响应的中间件
    match(method,url){
        let stack = []
        if(url==='/favicon.icon'){
            return stack  //返回空
        }

        // 获取routes
        let curRoutes = []
        curRoutes = curRoutes.concat(this.routes.all)
        // 获取post和get方法 并将两个数组拼接
        curRoutes = curRoutes.concat(this.routes[method])


        curRoutes.forEach(routeInfo => {
            // 判断两路径是否符合 
            if(url.indexOf(routeInfo.path) === 0){
                stack =stack.concat(routeInfo.stack)
            }
        })
        return stack
    }
    
    // 核心的next的机制实现 
    handle(req,res,stack){
        const next = ()=>{
            // 拿到第一个匹配的中间件
            // 注意shift()方法是拿到值 并删除 所以只要next()方法就会一直执行下去
            const middleware = stack.shift()
            if(middleware){
            // 执行中间件的函数
                middleware(req,res,next)
            }
        }
        next()
    }

    callback(){
        return (req,res)=>{
            // res.json函数就是下面代码组成的
            res.json = (data)=>{
                // 设置json格式
                res.setHeader('Content-type','application/json')
                res.end(
                    JSON.stringify(data)
                )
            }
            const url = req.url
            const method = req.method.toLowerCase()
            // 用match函数获得中间件的列表
            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()
}

接下来有一段测试代码,测试上述功能是否可以跑通
文件test.js

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('get /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.listen(3000, () => {
    console.log('server is running on port 8000')
})

用node test 运行之后
打开本地的 http://127.0.0.1:3000/api/get-cookie 情况如下

在这里插入图片描述

在这里插入图片描述
说明基本完成了功能

注:菜鸟学习笔记,如有错误,感谢评论指正,如有侵权,商讨删除

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值