我的编程空间,编程开发者的网络收藏夹
学习永远不晚

nodejs中间件Koa和Express有什区别

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

nodejs中间件Koa和Express有什区别

这篇文章将为大家详细讲解有关nodejs中间件Koa和Express有什区别,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

Koa用起来非常方便——比之express,它“完美中间件”的设计让功能之间看起来非常简洁!笔者在项目中就曾这样使用过:

const Koa=require('koa')const app=new Koa()const Router=require('koa-router')const router=new Router()const cors=require('koa2-cors')const koaBody=require('koa-body')const ENV='test-mpin2'app.use(cors({origin:['http://localhost:9528'],   // 也可以写为:['*']credentials:true}))app.use(koaBody({multipart:true}))app.use(async(ctx,next)=>{console.log('访问全局中间件')ctx.state.env=ENV   // 全局缓存await next()})const playlist=require('./controller/playlist.js')router.use('/playlist',playlist.routes())const blog=require('./controller/blog.js')router.use('/blog',blog.routes())app.use(router.routes()).use(router.allowedMethods())app.listen(3000,()=>{console.log('服务已开启')})

它将路由router抽离出去作为单独的中间件使用,则app只负责全局处理。还比如:

// 最外层中间件,可以用于兜底 Koa 全局错误app.use(async (ctx, next) => {  try {    // 执行下一个中间件    await next();  } catch (error) {    console.log(`[koa error]: ${error.message}`)  }});// 第二层中间件,可以用于日志记录app.use(async (ctx, next) => {  const { req } = ctx;  console.log(`req is ${JSON.stringify(req)}`);  await next();  console.log(`res is ${JSON.stringify(ctx.res)}`);});

简单实现一个Koa吧!

如上代码,我们看 Koa 实例,通过use方法注册和串联中间件,其源码的简单实现可以表述为:

use(fn) {    this.middleware.push(fn);    return this;}

我们将中间件存储到this.middleware数组中,那么中间件是如何被执行的呢?参考下面源码:

// 通过 createServer 方法启动一个 Node.js 服务listen(...args) {    const server = http.createServer(this.callback());    server.listen(...args);}

Koa 框架通过 http 模块的 createServer 方法创建一个 Node.js 服务,并传入 this.callback() 方法, callback源码简单实现如下:

callback(){const fn=compose(this.middlewareList)return (req,res)=>{const ctx=createContext(req,res)return this.handleRequest(ctx,fn)}}handleRequest(ctx, fn) {    const onerror = err => ctx.onerror(err);    // 将 ctx 对象传递给中间件函数 fn    return fn(ctx).catch(onerror);}

如上代码,我们将 Koa 一个中间件组合和执行流程梳理为以下步骤:

  • 通过一个方法(我们称为compose)组合各种中间件,返回一个中间件组合函数fn

  • 请求过来时,会先调用handleRequest方法,该方法完成:

    • 调用createContext方法,对该次请求封装出一个ctx对象;

    • 接着调用this.handleRequest(ctx, fn)处理该次请求。

其中,核心过程就是使用compose方法组合各种中间件 —— 这是一个单独的方法,它应该不受Koa其余方法的约束。其源码简单实现为:

// 组合中间件// 和express中的next函数意义一样function compose(middlewareList){// return function意思是返回一个函数return function(ctx,next){// 各种中间件调用的逻辑function dispatch(i){const fn=middlewareList[i] || nextif(fn){try{// koa中都是async,其返回的是一个promise(对象)return Promise.resolve(fn(ctx,function next(){return dispatch(i+1)}))}catch(err){return Promise.reject(err)}}else{return Promise.resolve()}}return dispatch(0)}}

其功能可以表示为这样(非源码):

async function middleware1() {  //...  await (async function middleware2() {    //...    await (async function middleware3() {      //...    });    //...  });  //...}

到这里我们其实可以“初窥”其原理,有两点:

  • Koa 的中间件机制被社区形象地总结为洋葱模型;

所谓洋葱模型,就是指每一个 Koa 中间件都是一层洋葱圈,它即可以掌管请求进入,也可以掌管响应返回。换句话说:外层的中间件可以影响内层的请求和响应阶段,内层的中间件只能影响外层的响应阶段。

  • dispatch(n)对应第 n 个中间件的执行,在使用中即第 n 个中间件可以通过await next()来“插入”执行下一个中间件,同时在最后一个中间件执行完成后,依然有恢复执行的能力。即:通过洋葱模型,await next()控制调用后面的中间件,直到全局没有可执行的中间件且堆栈执行完毕,最终“原路返回”至第一个执行next的中间件。这种方式有个优点,特别是对于日志记录以及错误处理等全局功能需要非常友好。

Koa1 的中间件实现利用了 Generator 函数 + co 库(一种基于 Promise 的 Generator 函数流程管理工具),来实现协程运行。本质上,Koa v1 中间件和 Koa v2 中间件思想是类似的,只不过 Koa v2 改用了 Async/Await 来替换 Generator 函数 + co 库,整体实现更加巧妙,代码更加优雅。—— from《狼书》

经过上述部分源码的描述,我们就可以采用es6的方式将其组合起来:

// myKoa.js文件const http=require('http')function compose(){}   //见上class LikeKoa2{constructor() {    this.middlewareList=[]}use(){}   //见上// 把所有的req,res属性、事件都交给ctx(这里只是简写)createContext(req,res){const ctx={req,res}// 比如ctx.query=req,queryreturn ctx}handleRequest(){}   //见上callback(){}   //见上listen(){}   //见上}// koa和express的不同之一:// express在调用时直接调用函数:const app=express();所以暴露出去new过的对象——具体见下面链接中代码// 但是koa调用时以类的方式:const app=new Koa();所以直接暴露出去module.exports=LikeKoa2

那use方法和其余方法并不相通,它是如何被执行的呢?执行了createServer后是不是相当于建立了一个通道、挂载了一个监听函数呢?
这一点恐怕就要到Node的源码中一探究竟了…


对比 Koa,聊聊 Express 原理

说起 Node.js 框架,我们一定忘不了 Express —— 不同于 Koa,它继承了路由、静态服务器和模板引擎等功能,虽然比之Koa显得“臃肿”了许多,但看上去比 Koa 更像是一个框架。通过学习 Express 源码,笔者简单的总结了它的工作机制:

  • 通过app.use方法注册中间件。

  • 一个中间件可以理解为一个 Layer 对象,其中包含了当前路由匹配的正则信息以及 handle 方法。

  • 所有中间件(Layer 对象)使用stack数组存储起来。

  • 当一个请求过来时,会从 req 中获取请求 path,根据 path 从stack中找到匹配的 Layer,具体匹配过程由router.handle函数实现。

  • router.handle函数通过next()方法遍历每一个 layer 进行比对:

    • next()方法通过闭包维持了对于 Stack Index 游标的引用,当调用next()方法时,就会从下一个中间件开始查找;

    • 如果比对结果为 true,则调用layer.handle_request方法,layer.handle_request方法中会调用next()方法 ,实现中间件的执行。

通过上述内容,我们可以看到,Express 其实是通过 next() 方法维护了遍历中间件列表的 Index 游标,中间件每次调用next()方法时,会通过增加 Index 游标的方式找到下一个中间件并执行。它的功能就像这样:

((req, res) => {  console.log('第一个中间件');  ((req, res) => {    console.log('第二个中间件');    (async(req, res) => {      console.log('第三个中间件');      await sleep(2000)      res.status(200).send('hello')    })(req, res)    console.log('第二个中间件调用结束');  })(req, res)  console.log('第一个中间件调用结束')})(req, res)

如上代码,Express 中间件设计并不是一个洋葱模型,它是基于回调实现的线形模型,不利于组合,不利于互操,在设计上并不像 Koa 一样简单。而且业务代码有一定程度的侵扰,甚至会造成不同中间件间的耦合。

express的简单实现笔者已上传至腾讯微云,需要者可自行查看&下载:express的简单实现

关于“nodejs中间件Koa和Express有什区别”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

nodejs中间件Koa和Express有什区别

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

nodejs中间件Koa和Express有什区别

这篇文章将为大家详细讲解有关nodejs中间件Koa和Express有什区别,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。Koa用起来非常方便——比之express,它“完美中间件”的设计让功能之间看起来
2023-06-06

nodejs里的koa-static中间件是什么

这篇文章主要介绍“nodejs里的koa-static中间件是什么”,在日常操作中,相信很多人在nodejs里的koa-static中间件是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”nodejs里的k
2023-06-07

nodejs和JavaScript有什么区别

这期内容当中小编将会给大家带来有关nodejs和JavaScript有什么区别,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。JavaScript的特点1.JavaScript主要用来向HTML页面添加交互
2023-06-14

Linux中[./]和[/]和[.]之间的区别有什么

本篇文章为大家展示了Linux中[./]和[/]和[.]之间的区别有什么,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。/是指根目录,就和Windows的我的电脑那个位置差不多。./是指用户所在的当前
2023-06-28

Shell $*和$@之间有什么区别

本篇内容主要讲解“Shell $*和$@之间有什么区别”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Shell $*和$@之间有什么区别”吧!$* 和 $@ 都表示传递给函数或脚本的所有参数,本
2023-06-09

Java中Sring和StringBuffer、StringBuilder间有什么区别

这篇“Java中Sring和StringBuffer、StringBuilder间有什么区别”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一
2023-06-27

this关键字在NodeJS和浏览器中有什么区别

今天就跟大家聊聊有关this关键字在NodeJS和浏览器中有什么区别,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。var type = 1function toWhere(){thi
2023-06-06

Vue中的插件和组件有什么区别

这篇文章主要介绍了Vue中的插件和组件有什么区别的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Vue中的插件和组件有什么区别文章都会有所收获,下面我们一起来看看吧。一、组件是什么回顾以前对组件的定义:组件就是把
2023-06-30

URL和URI之间有什么区别

URL和URI之间的区别是:1、URI是用于标识互联网上的资源的字符串序列,而URI并不关注资源的位置,而只关注它的标识符;2、URL提供了关于资源在互联网上位置的详细信息,而URI是一种更广义的概念,不仅涵盖了URL,还包括了用于标识资源
2023-08-14

MariaDB和MySQL之间有什么区别

MariaDB和MySQL是两种关系型数据库管理系统,它们之间有以下几个区别:开发者:MariaDB是MySQL的一个分支,由MySQL的原始开发者创建,因此两者在很多方面非常相似。然而,MariaDB有自己的开发团队和社区支持,所以在一些
MariaDB和MySQL之间有什么区别
2024-04-09

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录