0

0

nodejs中的中间件是什么意思

青灯夜游

青灯夜游

发布时间:2021-10-29 15:51:43

|

3411人浏览过

|

来源于php中文网

原创

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

nodejs中的中间件是什么意思

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

中间件概念

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

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

1.png

                                                          中间件工作模型

中间件机制核心实现

中间件是从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 start
middleware2 start
middleware3 start

如果中间件中有异步操作,需要在异步操作的流程结束后再调用next()方法,否则中间件不能按顺序执行。改写middleware2中间件:

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

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

middleware1 start
middleware2 start
middleware3 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()
}

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

全诚商城生成HTML多用户版
全诚商城生成HTML多用户版

1、什么是店中店?店中店是全诚商多用户版的一大特色,它既是独立的个体,又具有群集功能。我们做个例子说明:假设尊贵的您现实生活中租赁了一个店面,店面空间很大,您可以把您的店面分割成很多独立空间再向别人转租,这样您可以额外获得一部分租赁费用收入,借以减少你的个人租赁费用投入,还能起到活跃销售场所的气氛,俗话说:货卖一堆吗。你租赁的店面可以完全分割成很多空间向外转租,也可以自己保留一块空间为自己销售商品

下载
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框架提出的洋葱圈模型,即每一层中间件相当于一个球面,当贯穿整个模型时,实际上每一个球面会穿透两次。

2.png

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)
      }
    }
  }
}

koa中间件列表地址:https://github.com/koajs/koa/wiki 

总结

本文主要介绍了中间件的概念、为何引入中间件以及中间件机制的核心实现。中间件机制使得Web应用具备良好的可扩展性和组合性。

在实现中间件时,单个中间件应该足够简单,职责单一。由于每个请求都会调用中间件相关代码,中间件的代码应该高效,必要的时候可以缓存重复获取的数据。在对不同的路由使用中间件时,还应该考虑到不同的中间件应用到不同的路由上。

【推荐学习:《nodejs 教程》】

相关文章

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
c++ 根号
c++ 根号

本专题整合了c++根号相关教程,阅读专题下面的文章了解更多详细内容。

70

2026.01.23

c++空格相关教程合集
c++空格相关教程合集

本专题整合了c++空格相关教程,阅读专题下面的文章了解更多详细内容。

73

2026.01.23

yy漫画官方登录入口地址合集
yy漫画官方登录入口地址合集

本专题整合了yy漫画入口相关合集,阅读专题下面的文章了解更多详细内容。

298

2026.01.23

漫蛙最新入口地址汇总2026
漫蛙最新入口地址汇总2026

本专题整合了漫蛙最新入口地址大全,阅读专题下面的文章了解更多详细内容。

471

2026.01.23

C++ 高级模板编程与元编程
C++ 高级模板编程与元编程

本专题深入讲解 C++ 中的高级模板编程与元编程技术,涵盖模板特化、SFINAE、模板递归、类型萃取、编译时常量与计算、C++17 的折叠表达式与变长模板参数等。通过多个实际示例,帮助开发者掌握 如何利用 C++ 模板机制编写高效、可扩展的通用代码,并提升代码的灵活性与性能。

17

2026.01.23

php远程文件教程合集
php远程文件教程合集

本专题整合了php远程文件相关教程,阅读专题下面的文章了解更多详细内容。

114

2026.01.22

PHP后端开发相关内容汇总
PHP后端开发相关内容汇总

本专题整合了PHP后端开发相关内容,阅读专题下面的文章了解更多详细内容。

79

2026.01.22

php会话教程合集
php会话教程合集

本专题整合了php会话教程相关合集,阅读专题下面的文章了解更多详细内容。

94

2026.01.22

宝塔PHP8.4相关教程汇总
宝塔PHP8.4相关教程汇总

本专题整合了宝塔PHP8.4相关教程,阅读专题下面的文章了解更多详细内容。

74

2026.01.22

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
快速入门Node.JS全套完整版
快速入门Node.JS全套完整版

共83课时 | 8.4万人学习

nodejs开发基础教程
nodejs开发基础教程

共15课时 | 4.5万人学习

JavaScript设计模式视频教程
JavaScript设计模式视频教程

共28课时 | 5.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号