本文共 3505 字,大约阅读时间需要 11 分钟。
中间件概念
在Node.js环境中,中间件的概念主要用于封装处理Http请求的细节功能。每次Http请求通常会涉及诸多工作流程,如日志记录、IP过滤、查询字符串解析、Cookie处理等。然而,这些基础设施的处理往往会让开发者分心,影响业务逻辑的实现。因此,引入中间件的目的是为了隔离和简化基础设施与业务逻辑之间的交互,提升开发效率。
中间件的工作原理类似于Java中的过滤器机制。在实际的业务处理之前,中间件会被调用进行预处理。其工作流程可以通过下图所示的模型来理解。
中间件机制核心实现
中间件的核心作用是处理从请求开始到响应结束的整个流程。一个基本的中间件形式可以表示为:
const middleware = (req, res, next) => { // TODO next()} 通过以下两种方式的实现,可以更直观地理解中间件的工作机制。
方式一:简单的中间件定义
定义三个简单的中间件:
const middleware1 = (req, res, next) => { console.log('middleware1 start') next()}const middleware2 = (req, res, next) => { console.log('middleware2 start') next()}const middleware3 = (req, res, next) => { console.log('middleware3 start') next()} 将中间件组合使用:
const middlewares = [middleware1, middleware2, middleware3]function run(req, res) { const next = () => { const middleware = middlewares.shift() if (middleware) { middleware(req, res, next) } } next()}run() 执行结果:
middleware1 startmiddleware2 startmiddleware3 start
当中间件包含异步操作时,需要在异步流程完成后才能调用next()方法。例如:
const middleware2 = (req, res, next) => { console.log('middleware2 start') new Promise(resolve => { setTimeout(() => resolve(), 1000) }).then(() => { next() })} 执行结果与之前一致,但middleware3会在middleware2异步完成后执行。
解决方式二:使用Promise优化
为了在异步操作后正确调用next(),可以将next()方法的返回值封装为Promise对象。改写run()方法:
function run(req, res) { const next = () => { const middleware = middlewares.shift() if (middleware) { return Promise.resolve(middleware(req, res, next)) } else { return Promise.resolve("结束") } } next()} 中间件的调用方式需改写为:
const middleware1 = (req, res, next) => { console.log('middleware1 start') return next().then(() => { console.log('middleware1 end') })}const middleware2 = (req, res, next) => { console.log('middleware2 start') return next().then(() => { console.log("2", result) return 'middleware2 end' })}const middleware3 = (req, res, next) => { console.log('middleware3 start') return next().then(() => { console.log("3", result) return 'middleware3 end' })} 运行结果:
middleware1 startmiddleware2 startmiddleware3 start
async/await实现
使用async/await方式实现中间件:
const middleware1 = async (req, res, next) => { console.log('middleware1 start') let result = await next() console.log("1", result)}const middleware2 = async (req, res, next) => { console.log('middleware2 start') let result = await next() console.log("2", result) return 'middleware2 end'}const middleware3 = async (req, res, next) => { console.log('middleware3 start') let result = await next() console.log("3", result) return 'middleware3 end'} 运行结果:
middleware1 startmiddleware2 startmiddleware3 start
koa2框架中的洋葱圈模型
Koa2框架的中间件实现更加优雅,采用洋葱圈模型。核心代码如下:
function compose(middleware) { if (!Array.isArray(middleware)) throw new TypeError('Middleware stack must be an array!') for (const fn of middleware) { if (typeof fn !== 'function') throw new TypeError('Middleware must be composed of functions!') } return function(context, next) { let index = -1 return dispatch(0) function dispatch(i) { if (i <= index) return Promise.reject(new Error('next() called multiple times')) index = i let fn = middleware[i] if (i === middleware.length) fn = next if (!fn) return Promise.resolve() try { return Promise.resolve(fn(context, dispatch.bind(null, i + 1))) } catch (err) { return Promise.reject(err) } } }} 参考来源:Koa2框架官方文档
总结
本文介绍了中间件的概念、引入的必要性以及其核心实现机制。中间件机制使得Web应用具有良好的可扩展性和组合性。每个中间件应保持职责单一,确保代码高效且必要时可缓存数据。在实际应用中,需根据具体路由选择中间件,以提升整体应用性能和用户体验。
转载地址:http://evjfk.baihongyu.com/