千家信息网

nodej中间件指的是什么意思

发表于:2024-12-05 作者:千家信息网编辑
千家信息网最后更新 2024年12月05日,这篇文章主要介绍了nodej中间件指的是什么意思,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。在nodejs中,中间件主要是指封装所有
千家信息网最后更新 2024年12月05日nodej中间件指的是什么意思

这篇文章主要介绍了nodej中间件指的是什么意思,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

在nodejs中,中间件主要是指封装所有Http请求细节处理的方法,是从Http请求发起到响应结束过程中的处理方法。中间件的行为比较类似Java中过滤器的工作原理,就是在进入具体的业务处理之前,先让过滤器处理。

本教程操作环境:windows7系统、nodejs 12.19.0版、Dell G3电脑。

中间件概念

在NodeJS中,中间件主要是指封装所有Http请求细节处理的方法。一次Http请求通常包含很多工作,如记录日志、ip过滤、查询字符串、请求体解析、Cookie处理、权限验证、参数验证、异常处理等,但对于Web应用而言,并不希望接触到这么多细节性的处理,因此引入中间件来简化和隔离这些基础设施与业务逻辑之间的细节,让开发者能够关注在业务的开发上,以达到提升开发效率的目的。

中间件的行为比较类似Java中过滤器的工作原理,就是在进入具体的业务处理之前,先让过滤器处理。它的工作模型下图所示。

                    中间件工作模型

中间件机制核心实现

中间件是从Http请求发起到响应结束过程中的处理方法,通常需要对请求和响应进行处理,因此一个基本的中间件的形式如下:

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()方法,否则中间件不能按顺序执行。改写middleware2中间件:

const middleware2 = (req, res, next) => {  console.log('middleware2 start')  new Promise(resolve => {    setTimeout(() => resolve(), 1000)  }).then(() => {    next()  })}

执行结果与之前一致,不过middleware3会在middleware2异步完成后执行。

middleware1 startmiddleware2 startmiddleware3 start

有些中间件不止需要在业务处理前执行,还需要在业务处理后执行,比如统计时间的日志中间件。在方式一情况下,无法在next()为异步操作时再将当前中间件的其他代码作为回调执行。因此可以将next()方法的后续操作封装成一个Promise对象,中间件内部就可以使用next.then()形式完成业务处理结束后的回调。改写run()方法如下:

function run (req, res) {  const next = () => {    const middleware = middlewares.shift()    if (middleware) {      // 将middleware(req, res, next)包装为Promise对象      return Promise.resolve(middleware(req, res, next))    }  }  next()}

中间件的调用方式需改写为:

const middleware1 = (req, res, next) => {  console.log('middleware1 start')  // 所有的中间件都应返回一个Promise对象  // Promise.resolve()方法接收中间件返回的Promise对象,供下层中间件异步控制  return next().then(() => {    console.log('middleware1 end')  })}
const middleware1 = (req, res, next) => {    console.log('middleware1 start')    // 所有的中间件都应返回一个Promise对象    // Promise.resolve()方法接收中间件返回的Promise对象,供下层中间件异步控制    return next().then((res) => {      console.log("1",res)      return 'middleware1 end';    })  }    const middleware2 = (req, res, next) => {    console.log('middleware2 start')    // 所有的中间件都应返回一个Promise对象    // Promise.resolve()方法接收中间件返回的Promise对象,供下层中间件异步控制    // console.log("next()",next())    return next().then((res) => {      console.log("2",res)      return 'middleware2 end'    })  }  const middleware3 = (req, res, next) => {    console.log('middleware3 start')    return next().then((res) => {      console.log("3",res)      return 'middleware3 end'    })  }const middlewares = [middleware1, middleware2, middleware3]function run (req, res) {    const next = () => {      const middleware = middlewares.shift()      if (middleware) {        //   console.log("next",next)        // 将middleware(req, res, next)包装为Promise对象        return Promise.resolve(middleware(req, res, next))      }else {        return Promise.resolve("结束");      }    }    next()  }run() // 模拟一次请求发起

结果:

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';  }const middlewares = [middleware1, middleware2, middleware3]function run (req, res) {    const next = () => {      const middleware = middlewares.shift()      if (middleware) {        //   console.log("next",next)        // 将middleware(req, res, next)包装为Promise对象        return Promise.resolve(middleware(req, res, next))      }else {        return Promise.resolve("结束");      }    }    next()  }run() // 模拟一次请求发起

以上描述了中间件机制中多个异步中间件的调用流程,实际中间件机制的实现还需要考虑异常处理、路由等。

express框架中,中间件的实现方式为方式一,并且全局中间件和内置路由中间件中根据请求路径定义的中间件共同作用,不过无法在业务处理结束后再调用当前中间件中的代码。koa2框架中中间件的实现方式为方式二,将next()方法返回值封装成一个Promise,便于后续中间件的异步流程控制,实现了koa2框架提出的洋葱圈模型,即每一层中间件相当于一个球面,当贯穿整个模型时,实际上每一个球面会穿透两次。

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) {      // index会在next()方法调用后累加,防止next()方法重复调用      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 {        // 核心代码        // 包装next()方法返回值为Promise对象        return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));      } catch (err) {        // 遇到异常中断后续中间件的调用        return Promise.reject(err)      }    }  }}

感谢你能够认真阅读完这篇文章,希望小编分享的"nodej中间件指的是什么意思"这篇文章对大家有帮助,同时也希望大家多多支持,关注行业资讯频道,更多相关知识等着你来学习!

0