下面代码有详细注释
文件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 情况如下
说明基本完成了功能
注:菜鸟学习笔记,如有错误,感谢评论指正,如有侵权,商讨删除