1、like-express.js文件
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
// 从第二个参数开始,转换为数组,存入 stack
info.stack = slice.call(arguments, 1)
} else {
info.path = '/'
// 从第一个参数开始,转换为数组,存入 stack
info.stack = slice.call(arguments, 0)
}
return info
}
use () {
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)
}
match (method, url) {
let stack = []
if (url === '/favicon.ico') {
return stack
}
// 获取 routes
let curRoutes = []
curRoutes = curRoutes.concat(this.routes.all)
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 = () => {
// 拿到第一个匹配的中间件
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) {
const server = http.createServer(this.callback())
server.listen(...args)
}
}
// 工厂函数
module.exports = () => {
return new LikeExpress
}
2、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(8000, () => {
console.log('server is running on port 8000')
})
1、like-koa2.js文件
const http = require('http')
// 组合中间件
function compose(middlewareList) {
return function (ctx) {
function dispatch(i) {
const fn = middlewareList[i]
try {
return Promise.resolve(
fn(ctx, dispatch.bind(null, i + 1))
)
} catch (err) {
return Promise.reject(err)
}
}
return dispatch(0)
}
}
class LikeKoa2 {
constructor () {
this.middlewareList = []
}
use (fn) {
this.middlewareList.push(fn)
return this
}
createContext (req, res) {
const ctx = {
req,
res
}
ctx.query = req.query
return ctx
}
handleRequest (ctx, fn) {
return fn(ctx)
}
callback () {
const fn = compose(this.middlewareList)
return (req, res) => {
const ctx = this.createContext(req, res)
return this.handleRequest(ctx, fn)
}
}
listen (...args) {
const server = http.createServer(this.callback())
server.listen(...args)
}
}
module.exports = LikeKoa2
2、test.js文件
const Koa = require('./like-koa2');
const app = new Koa();
// logger
app.use(async (ctx, next) => {
await next()
const rt = ctx['X-Response-Time'];
console.log(`${ctx.req.method} ${ctx.req.url} - ${rt}`);
});
// x-response-time
app.use(async (ctx, next) => {
const start = Date.now();
await next();
const ms = Date.now() - start;
ctx['X-Response-Time'] = `${ms}ms`;
});
// response
app.use(async ctx => {
ctx.res.setHeader('Content-Type', 'application')
ctx.res.end('This is like koa2');
});
app.listen(8000)
注:大佬写的代码,起一篇博客特此记录,面试可能会遇到。所以反复回顾。