likeExpress.js 如下所示:
const http = require('http');
const slice = Array.prototype.slice;
class LikeExpress {
constructor() {
this.routes = {
all: [], // 存放通用的中间件
get: [], // 存放get请求的中间件
post: [] // 存放Post请求的中间件
}
}
// 注册中间件函数
register(path) {
let info = {}
// 如果传进来的路径是一个字符串类型的 则将第2个参数开始的参数都作为中间件
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() {
// 如果实例调用了use方法,则注册通用的中间件 放到all数组中
const info = this.register.apply(this, arguments);
this.routes.all.push( info );
}
get() {
// 如果实例调用了get方法 则将中间件放进get数组中
const info = this.register.apply(this, arguments);
this.routes.get.push(info)
}
post() {
// 如果实例调用了post方法 则将中间件放进post数组中
const info = this.register.apply(this, arguments);
this.routes.post.push( info );
}
// 匹配函数
match( method, url ) {
let stack = [] // 用来存放中间件的数组
// 当我们访问网站的时候会发一个/favicon.ico请求 所以需要做一下处理
if (url === '/favicon.ico') {
return stack
}
let curRoutes = [] // 声明一个存放当前路由的数组
curRoutes = curRoutes.concat(this.routes.all) // 先拿到公共的路由 也就是app.use()
curRoutes = curRoutes.concat(this.routes[method]) // 再通过传进来的method拿到对应请求的路由
// 循环遍历当前拿到的路由数组
curRoutes.forEach((routeInfo) => {
// 判断客户端的url地址 和 当前路由的path能不能匹配上 能匹配上说明注册了这个中间件
if (url.indexOf( routeInfo.path ) === 0) {
// 把匹配上的中间件都给stack数组
stack = stack.concat(routeInfo.stack)
}
})
return stack
}
// 核心代码
handle(req, res, stack) {
// 我们创建一个next函数
const next = () => {
// 首先从中间件列表中拿到第一个中间件
const middleware = stack.shift()
// 如果有中间件,则执行中间件,并且把req,res,next传递给它做参数。
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)
}
}
// 利用node.js提供的http模块启一个http服务。
listen(...args) {
const server = http.createServer(this.callback())
server.listen(...args)
}
}
module.exports = () => {
return new LikeExpress()
}
让我们调用一下这个袖珍版的express试试效果
test.js
const express = require('./like-express')
const app = express();
app.use((req, res, next) => {
console.log('请求开始...', req.method, req.url)
next()
})
app.use((req, res, next) => {
console.log('处理cookie...')
req.cookie = {
userId: 'abcd123'
}
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(8900, () => {
console.log('server is runing at port 8900.')
})
最后,我们看一下效果 使用node启动服务:
事实证明,我们写的袖珍版express还是通过了考验的。