Express在使用中间件时主要用到了下面几个方法:
use方法: path非必传,可传入多个中间件;path部分匹配
get方法:其他同use方法;path需要全匹配
post方法:其他同use方法;path需要全匹配
listen方法:监听某个http端口,执行其他回调
like-express.js 代码:
const http = require('http')
class LikeExpressTest {
constructor() {
// 存放所有注册的中间件
this.middlewares = {
all: [],
get: [],
post: []
}
}
// 获取注册时path和中间件的表
getRoute(argList) {
const [firstParam] = argList
let routes = []
if (typeof firstParam !== 'string') {
// 没有传path; path就是 '/'
argList.forEach(item => {
const infoObj = { path: '/', route: item }
routes.push(infoObj)
})
} else {
let routesTmp = argList.slice(1)
routesTmp.forEach(item => {
const infoObj = { path: firstParam, route: item }
routes.push(infoObj)
})
}
return routes
}
use() {
const argList = [...arguments]
this.middlewares.all.push(...this.getRoute(argList))
}
get() {
const argList = [...arguments]
this.middlewares.get.push(...this.getRoute(argList))
}
post() {
const argList = [...arguments]
this.middlewares.post.push(...this.getRoute(argList))
}
// 获取 path,method相匹配的中间件
checkRoutes(path, method) {
const result = []
// all:所有path为'/',或者左到右匹配了部分path的中间件
this.middlewares.all.forEach((item) => {
if(item.path === '/' || path.indexOf(item.path + '/') === 0) {
result.push(item.route)
}
})
// 非all: 和链接上path 相等的中间件
this.middlewares[method].forEach(item => {
if(item.path === path) {
result.push(item.route)
}
})
return result
}
callback() {
return (req, res) => {
res.setHeader("Content-type", "application/json");
const path = req.url.split('?')[0]
const method = req.method.toLowerCase()
// 获取和path 和 method匹配的中间件
const routes = this.checkRoutes(path, method)
res.json = (data) => {
res.end(JSON.stringify(data))
}
// 取出下一个中间件,如果存在,去执行
const next = () => {
const middleware = routes.shift()
if (middleware) {
middleware(req, res, next)
} else {
res.end('')
}
}
next()
}
}
listen() {
const server = http.createServer(this.callback())
server.listen(...arguments)
}
}
module.exports = LikeExpressTest
在test.js 中调用这个Express:
const express = require('./like-express')
const app = new express()
app.use((req, res, next) => {
console.log('请求开始...', req.method, req.url)
next()
})
app.use((req, res, next) => {
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()
})
app.post('/api', (req, res, next) => {
console.log('post api路由')
next()
})
function loginCheck(req, res, next) {
setTimeout(() => {
console.log('模拟登陆成功 **')
next()
});
}
app.get('/api/get-cookie', loginCheck, (req, res, next) => {
console.log('get cookie ***** ')
res.json({
errno: 0,
msg: 'xixixi'
})
})
app.post('/api/user/update', loginCheck, (req, res, next) => {
res.json({
errno: 0,
data: {name: 'haha', id: 1}
})
})
app.listen(5000, () => {
console.log('5000 端口,欢迎访问~~')
})
执行node test.js ,然后访问链接 http://localhost:5000/api/get-cookie ,执行结果是:
请求开始... GET /api/get-cookie
处理cookie... ***
处理api路由
模拟登陆成功 **
get cookie *****
以上就是中间件的注册和调用的方法。
难点是 callback 方法中,next方法的实现。在next内部调用了自己,实现中间件的循环调用。