手机版

谈Node.js中间件模式

时间:2021-08-31 来源:互联网 编辑:宝哥软件园 浏览:

中间件在Node.js中的应用非常广泛,它一般是指一种特定的设计模式,一系列的处理单元、过滤器和处理程序,以函数的形式存在,连接在一起形成一个异步队列,完成对任何数据的预处理和后处理。

它的优势在于灵活性:使用中间件,我们可以用很少的操作得到一个插件,我们可以用最简单的方法将新的过滤器和处理程序扩展到现有的系统。

通用中间件模式

在中间件模式下,最基本的组件是中间件管理器,可以用来组织和执行中间件功能,如图所示:

为了实现中间件模式,最重要的实现细节是:

您可以通过调用use()函数来注册新的中间件。通常只能在高压包的末端添加新的中间件,但并没有严格要求这样做;当接收到需要处理的新数据时,在不执行的过程中依次调用注册的中间件。每个中间件接受前一个中间件的执行结果作为输入值;每个中间件都可以通过简单地不调用其销毁函数或将错误传递给回调函数来停止进一步的数据处理。当错误发生时,它通常会触发另一个专门处理错误的中间件的执行。至于如何处理传输的数据,目前没有严格的规定,一般有几种方式

通过添加属性和方法来增强;替换数据;一些处理的结果;确保要处理的原始数据不变,并始终返回一个新副本作为处理结果。具体的处理方式取决于中间件管理器的实现方式和中间件本身要完成的任务类型。

举一个从《Node.js 设计模式 第二版》实现消息传递库中间件管理器的例子:

类ZmqMiddlewareManager {构造函数(套接字){ this.socket=socket//两个列表分别存储了两种中间件功能:接收信息和发送信息。this . inboundmiddleware=[];this . outboundmiddleware=[];socket.on('message ',message={ this . execute middleware(this . inboundmiddleware,{ data : message });});}发送(数据){ const message={ data };this . ExecuteMetiddleWare(this . OutBoundMidMeDIa,message,()={ this . socket . send(message . data);});}使用(中间件){ if(middleware . inbound){ this . inbound middleware . push(middleware . inbound);} if(中间件. outbound){ this . outbound middleware . push(中间件. outbound);} } exucuteMiddleware(中间件,arg,finish) {函数迭代器(index){ if(index===middleware . length){ return finish finish();}中间件[索引]。调用(this,arg,err={ if(err) { return console.log('出现错误: ' err . message);} iterator.call(this,index);});} iterator.call(this,0);}}接下来,只需创建中间件,分别在入站和出站中编写中间件函数,执行后再调用next()。例如:

const zmqm=new ZmqMiddlewareManager();zmqm.use({ inbound:函数(message,next){ console . log(' input message : ',message . data);next();},outbound:函数(message,next){ console . log(' output message : ',message . data);next();}});Express推广的中间件概念也差不多。快速中间件通常是这样的:

函数中使用的中间件(req,RES,next){ 0.} koa2

上面显示的中间件模型是通过回调函数实现的,但是现在有了一个时髦的Node.js框架,Koa2的中间件实现和之前描述的有些不同。Koa2中的中间件模式首先去掉了S2015中生成器实现的方法,兼容回调函数、转换后的生成器、异步和等待。

Koa2官方文档给出了一个关于中间件的洋葱模型,如下图所示:

从图中我们可以看到,先进入入境的的中间件函数在开往外地的中被放到了后面执行,那么究竟是为什么呢?带着这个问题我们去读一下Koa2的源码。

在KOA/lib/app。射流研究…中,先看构造函数,其它的都可以不管,关键就是这个。中间件,它是一个入境的队列:

构造函数(){超级();this.proxy=falsethis。中间件=[];这个。子域偏移量=2;这个。ENV=进程。ENV。node _ ENV | | '开发';这.上下文=对象.创建(上下文);这个. request=Object.create(请求);this.response=Object.create(响应);}和上面一样,在Koa2中也是用使用()来把中间件放入队列中:

使用{ if(fn)的类型!=='函数')抛出新类型错误('中间件必须是函数!');if(是生成器函数(fn)){ defert('对生成器的支持将在v3中删除。'有关如何转换旧中间件https://github。com/koajs/KOA/blob/master/docs/migration。医学博士')的示例,请参见文档;fn=convert(fn);}调试('使用%s,fn ._ name | | fn。name | | '-');这个。中间件。push(fn);归还这个;}接着我们看框架对端口监听进行了一个简单的封装:

//封装之前http.createServer(app.callback()).听着(.)听着(.args){ debug(' listen ');const server=http。CreateServer(这个。callback());return server.listen(.args);}中间件的管理关键就在于this.callback(),看一下这个方法:

回调(){ const fn=compose(this。中间件);if(!这个。侦听器计数(“错误”)。这个。on('错误',这。一个错误);const handleRequest=(req,RES)={ const CTX=this。创建上下文(请求、资源);返回this.handleRequest(ctx,fn);};返回handleRequest}这里的构成方法实际上是Koa2的一个核心模块KOA-compose(https://github。com/koajs/compose),在这个模块中封装了中间件执行的方法:

函数合成(中间件){ if(!Array.isArray(中间件))抛出新类型错误('中间件堆栈必须是数组!')用于(中间件的常量如果(fn)的类型!=='函数')抛出新类型错误('中间件必须由函数组成!')}/* * * @ param { Object } context * @ return { Promise } * @ API public */return function(context,next) { //最后调用的中间件# let index=-1返回dispatch(0)函数dispatch(I){ if(I=index)返回Promise。拒绝(新错误('下一个())调用了多次))索引=i让fn=中间件[i] if (i===中间件。长度)fn=下一个if(!fn)返回承诺.解决()尝试{回报承诺。解析(fn(context,dispatch.bind(null,I ^ 1));}捕获(错误){返回承诺。拒绝(错误)} } }可以看到,撰写通过递归对中间件队列进行了反序遍历,生成了一个承诺链,接下来,只需要调用承诺就可以执行中间件函数了:

handleRequest(ctx,fnMiddleware){ const RES=CTX。RESRES . status code=404 const one rror=err=CTX。一个错误;const handleResponse=()=response(CTX);完成(res,一个错误);返回中间件.然后(手柄响应).捕获(一个rror);}从源码中可以发现,下一个()中返回的是一个答应我,所以通用的中间件写法是:

app.use((ctx,next)={ const start=new Date();返回下一个()。然后(()={ const ms=new Date()-start;控制台。日志(` $ { CTX。方法} $ { CTX。URL }-$ { ms } ms `);});});当然如果要用异步非同步(异步)和等待也行:

app.use((ctx,next)={ const start=new Date();等待下一个();const ms=新日期()-开始;控制台。日志(` $ { CTX。方法} $ { CTX。URL }-$ { ms } ms `);});由于还有很多Koa1的项目中间件是基于生成器的,需要使用koa-convert来进行平滑升级:

const convert=必选(' KOA-convert ');app。使用(convert(function *(next)){ const start=new Date();接下来屈服;const ms=新日期()-开始;控制台。log(` $ { this。方法} $ { this。URL }-$ { ms } ms `);}));以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

版权声明:谈Node.js中间件模式是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。