文章详情

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

请输入下面的图形验证码

提交验证

短信预约提醒成功

nodejs中间件Koa和Express有什区别

2023-06-06 12:47

关注

这篇文章将为大家详细讲解有关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方法组合各种中间件 —— 这是一个单独的方法,它应该不受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 中间件都是一层洋葱圈,它即可以掌管请求进入,也可以掌管响应返回。换句话说:外层的中间件可以影响内层的请求和响应阶段,内层的中间件只能影响外层的响应阶段。

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 源码,笔者简单的总结了它的工作机制:

通过上述内容,我们可以看到,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

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯