在nodeJS中,中间件主要是指封装所有Http请求细节处理的方法,一次Http请求通常包含很多工作:如记录日志,IP过滤,查询字符串、请求体解析,cookie处理、权限验证、参数验证、异常处理等、但对web应用而言,并不希望接触到这么多细节性的处理,因此使用中间件来简化及隔离这些基础设施与业务逻辑之间的细节,让开发者更关注在业务的开发上,他的工作模式如下:
中间件机制核心实现
中间件是从Http请求发起到响应结束过程中的处理方法,通常需要对请求和响应进行处理,因此一个基本的中间件的形式如下:
const middleware = (req, res, next) => {
// TODO
next()
}
模拟最基本的中间件
// 定义简单的三个中间件
const httpMeth1 = (req, res, next) => {
console.log('我是请求1')
next()
}
const httpMeth2 = (req, res, next) => {
console.log('我是请求2')
next()
}
const httpMeth3 = (req, res, next) => {
console.log('我是请求3')
next()
}
// 中间件数组
const allHttpMeth = [httpMeth1, httpMeth2, httpMeth3]
function run (req, res) {
const next = () => {
// 获取中间件
const allHttpMethitem = allHttpMeth.shift()
if (allHttpMethitem) {
// 执行
allHttpMethitem(req, res, next)
}
}
next()
}
run() // 模拟请求发起
如果中间件中有异步操作,需要在异步操作的流程结束后再调用next()
方法,否则中间件不能按顺序执行
const httpMeth3 = (req, res, next) => {
// 如果中间件中有异步操作,需要在异步操作完成后再调用next
new Promise((resolve, reject) => {
console.log('我是请求3')
}).then(() => {
next()
})
}
有些中间件不止需要在业务处理前执行,还需要在业务处理后执行,比如统计时间的日志中间件。在方式一情况下,无法在next()
为异步操作时再将当前中间件的其他代码作为回调执行。因此可以将next()
方法的后续操作封装成一个Promise
对象,中间件内部就可以使用next.then()
形式完成业务处理结束后的回调。改写run()
方法如下:
// 定义简单的三个中间件
const httpMeth1 = (req, res, next) => {
return next().then((res) => {
console.log('我是请求1')
})
}
const httpMeth2 = (req, res, next) => {
return next().then((res) => {
console.log('我是请求2')
})
}
const httpMeth3 = (req, res, next) => {
// 如果中间件中有异步操作,需要在异步操作完成后再调用next
/* new Promise((resolve, reject) => {
console.log('我是请求3')
}).then(() => {
next()
}) */
return next().then((res) => {
console.log('我是请求3')
})
}
// 中间件数组
const allHttpMeth = [httpMeth1, httpMeth2, httpMeth3]
function run (req, res) {
const next = () => {
// 获取中间件
const allHttpMethitem = allHttpMeth.shift()
if (allHttpMethitem) {
// 执行
return Promise.resolve(allHttpMethitem(req, res, next))
} else {
return Promise.resolve('结束')
}
}
next()
}
run() // 模拟请求发起
}
async await 实现
// 定义简单的三个中间件
const httpMeth1 = (req, res, next) => {
return next().then((res) => {
console.log('我是请求1')
})
}
// 也可以用 async
const httpMeth2 = async (req, res, next) => {
console.log('我是请求2')
let result = await next()
console.log('2', result)
return 'httpMeth2 end'
}
const httpMeth3 = (req, res, next) => {
// 如果中间件中有异步操作,需要在异步操作完成后再调用next
/* new Promise((resolve, reject) => {
console.log('我是请求3')
}).then(() => {
next()
}) */
return next().then((res) => {
console.log('我是请求3')
})
}
// 中间件数组
const allHttpMeth = [httpMeth1, httpMeth2, httpMeth3]
function run (req, res) {
const next = () => {
// 获取中间件
const allHttpMethitem = allHttpMeth.shift()
if (allHttpMethitem) {
// 执行
return Promise.resolve(allHttpMethitem(req, res, next))
} else {
return Promise.resolve('结束')
}
}
next()
}
run() // 模拟请求发起
}