let middlewares = (_routerMiddlewares[url]) ? _routerMiddlewares[url].middlewares : [];
// put * path middlewares on the queue head
if (_routerMiddlewares['*']) {
middlewares = [].concat(_routerMiddlewares['*'].middlewares, middlewares);
}
组合好中间件后,执行这一段,将中间件 compose 后并返回一个函数,传入上下文 this 后,最后将 this.body 的值 resolve,即一般在最后一个中间件里,通过对 ctx.body 的赋值,实现云函数的对小程序端的返回:
概念回顾
在掘金开发者大会上,在推荐实践那里,我有提到一种云函数的用法,我们可以将相同的一些操作,比如用户管理、支付逻辑,按照业务的相似性,归类到一个云函数里,这样比较方便管理、排查问题以及逻辑的共享。甚至如果你的小程序的后台逻辑不复杂,请求量不是特别大,完全可以在云函数里面做一个单一的微服务,根据路由来处理任务。
用下面三幅图可以概括,我们来回顾一下:
比如这里就是传统的云函数用法,一个云函数处理一个任务,高度解耦。
第二幅架构图就是尝试将请求归类,一个云函数处理某一类的请求,比如有专门负责处理用户的,或者专门处理支付的云函数。
最后一幅图显示这里只有一个云函数,云函数里有一个分派任务的路由管理,将不同的任务分配给不同的本地函数处理。
tcb-router
介绍及用法为了方便大家试用,咱们腾讯云 Tencent Cloud Base 团队开发了 tcb-router,云函数路由管理库方便大家使用。
那具体怎么使用
tcb-router
去实现上面提到的架构呢?下面我会逐一举例子。架构一:一个云函数处理一个任务 这种架构下,其实不需要用到
tcb-router
,像普通那样写好云函数,然后在小程序端调用就可以了。云函数
小程序端
架构二: 按请求给云函数归类 此类架构就是将相似的请求归类到同一个云函数处理,比如可以分为用户管理、支付等等的云函数。
exports.main = async (event, context) => { const app = new TcbRouter({ event });
};
// 函数 pay const TcbRouter = require('tcb-router');
exports.main = async (event, context) => { const app = new TcbRouter({ event });
};
架构三: 由一个云函数处理所有服务
exports.main = async (event, context) => { const app = new TcbRouter({ event });
};
借鉴 Koa2 的中间件机制实现云函数的路由管理
小程序·云开发的云函数目前更推荐
async/await
的玩法来处理异步操作,因此这里也参考了同样是基于async/await
的 Koa2 的中间件实现机制。从上面的一些例子我们可以看出,主要是通过
use
和router
两种方法传入路由以及相关处理的中间件。use
只能传入一个中间件,路由也只能是字符串,通常用于 use 一些所有路由都得使用的中间件router
可以传一个或多个中间件,路由也可以传入一个或者多个。不过,无论是
use
还是router
,都只是将路由和中间件信息,通过_addMiddleware
和_addRoute
两个方法,录入到_routerMiddlewares
该对象中,用于后续调用serve
的时候,层层去执行中间件。最重要的运行中间件逻辑,则是在
serve
和compose
两个方法里。serve
里主要的作用是做路由的匹配以及将中间件组合好之后,通过compose
进行下一步的操作。比如以下这段节选的代码,其实是将匹配到的路由的中间件,以及*
这个通配路由的中间件合并到一起,最后依次执行。组合好中间件后,执行这一段,将中间件
compose
后并返回一个函数,传入上下文this
后,最后将this.body
的值resolve
,即一般在最后一个中间件里,通过对ctx.body
的赋值,实现云函数的对小程序端的返回:那么
compose
是怎么组合好这些中间件的呢?这里截取部份代码进行分析看完这里的代码,其实有点疑惑,怎么通过
Promise.resolve(handler(xxxx))
这样的代码逻辑可以推进中间件的调用呢?首先,我们知道,
handler
其实就是一个async function
,next
,就是dispatch.bind(null, i + 1)
比如这个:而我们知道,
dispatch
是返回一个Promise.resolve
或者一个Promise.reject
,因此在async function
里执行await next()
,就相当于触发下一个中间件的调用。当
compose
完成后,还是会返回一个function (context, next)
,于是就走到下面这个逻辑,执行fn
并传入上下文this
后,再将在中间件中赋值的this.body
resolve
出来,最终就成为云函数数要返回的值。看到
Promise.resolve
一个async function
,许多人都会很困惑。其实撇除next
这个往下调用中间件的逻辑,我们可以很好地将逻辑简化成下面这段示例: