请选择 进入手机版 | 继续访问电脑版

扫一扫,访问微社区

QQ登录

只需一步,快速开始

查看: 607|回复: 0

小程序·云开发的云函数路由高级玩法

[复制链接]

该用户从未签到

1

主题

0

帖子

14

积分

新手上路

Rank: 1

积分
14
发表于 2018-9-27 20:58:42 | 显示全部楼层 |阅读模式
您的域名(zixueh5.com)未获得授权,部分功能受到影响!


尊敬的用户:

  您好!非常感谢您能安装和关注本产品,为了产品的可持续发展和升级,众大云采集已经开始收费。

  向用户收费是为了给用户更可靠的保障和服务,所收取的费用主要用于产品的正常运作、研发和改进,希望各位能够理解和支持。

  另外,为了答谢新老客户,众大云采集3折优惠,原价980元,现在购买仅需290元,给您节省了690元。

  官方QQ群:23530791  客服QQ:2085244671

  购买域名授权请打开下面的网址:

http://www.0762home.com/zt/csdn123_news/pay_url.php?url=zixueh5.com

  购买域名授权之后所有的未授权提示将自动消失,图片也正常显示,域名授权永久有效终身可用,后续的升级更新也是免费的,一次购买一辈子都能用,无后顾之忧!

提示:为了您网站的内容安全,请不要发布违反国家法律法规的内容,您目前使用的是免费试用版,可以手动删除上面的未购买授权的提示,发布这篇文章!


  李成熙,腾讯云高级工程师。2014年度毕业加入腾讯AlloyTeam,先后负责过QQ群、花样直播、腾讯文档等项目。2018年加入腾讯云云开发团队。专注于性能优化、工程化和小程序服务。微博|知乎|Github概念回顾在掘金开发者 ...
 李成熙,腾讯云高级工程师。2014年度毕业加入腾讯AlloyTeam,先后负责过QQ群、花样直播、腾讯文档等项目。2018年加入腾讯云云开发团队。专注于性能优化、工程化和小程序服务。微博 | 知乎 | Github
概念回顾 
  在掘金开发者大会上,在推荐实践那里,我有提到一种云函数的用法,我们可以将相同的一些操作,比如用户管理、支付逻辑,按照业务的相似性,归类到一个云函数里,这样比较方便管理、排查问题以及逻辑的共享。甚至如果你的小程序的后台逻辑不复杂,请求量不是特别大,完全可以在云函数里面做一个单一的微服务,根据路由来处理任务。
  用下面三幅图可以概括,我们来回顾一下:
KNNrFgS1N33143mb.jpg
V8ne61Gz64uDS371.jpg
uaI8KL8DR1bD131D.jpg
Qt8QWTOyW313ZwL5.jpg
  比如这里就是传统的云函数用法,一个云函数处理一个任务,高度解耦。
cB8IZIYdIL6Ia8NI.jpg
  第二幅架构图就是尝试将请求归类,一个云函数处理某一类的请求,比如有专门负责处理用户的,或者专门处理支付的云函数。
Tjct9GgfTtzlf9EJ.jpg
  最后一幅图显示这里只有一个云函数,云函数里有一个分派任务的路由管理,将不同的任务分配给不同的本地函数处理。
 tcb-router 介绍及用法 
  为了方便大家试用,咱们腾讯云 Tencent Cloud Base 团队开发了tcb-router,云函数路由管理库方便大家使用。 
  那具体怎么使用tcb-router 去实现上面提到的架构呢?下面我会逐一举例子。 
  架构一:一个云函数处理一个任务 
  这种架构下,其实不需要用到tcb-router,像普通那样写好云函数,然后在小程序端调用就可以了。 
 云函数 
 // 函数 router 
exports.main = (event, context) => { 
return { 
  code:0, 
  message:'success'  
  }; 
};
小程序端 
 wx.cloud.callFunction({ 
  name:'router', 
  data: { 
  name:'tcb', 
  company:'Tencent'  
  } 
  }).then((res) => { 
console.log(res); 
  }).catch((e) => { 
console.log(e); 
});
  架构二: 按请求给云函数归类 
  此类架构就是将相似的请求归类到同一个云函数处理,比如可以分为用户管理、支付等等的云函数。
 云函数 
 // 函数 user  
const TcbRouter = require('tcb-router'); 
exports.main = async (event, context) => { 
const app = new TcbRouter({ event }); 
  app.router('register', async (ctx, next) => { 
await next(); 
  },async (ctx, next) => { 
await next(); 
  },async (ctx) => { 
  ctx.body = { 
  code:0, 
  message:'register success'  
  } 
  }); 
  app.router('login', async (ctx, next) => { 
await next(); 
  },async (ctx, next) => { 
await next(); 
  },async (ctx) => { 
  ctx.body = { 
  code:0, 
  message:'login success'  
  } 
  }); 
return app.serve(); 
}; 
// 函数 pay  
const TcbRouter = require('tcb-router'); 
exports.main = async (event, context) => { 
const app = new TcbRouter({ event }); 
  app.router('makeOrder', async (ctx, next) => { 
await next(); 
  },async (ctx, next) => { 
await next(); 
  },async (ctx) => { 
  ctx.body = { 
  code:0, 
  message:'make order success'  
  } 
  }); 
  app.router('pay', async (ctx, next) => { 
await next(); 
  },async (ctx, next) => { 
await next(); 
  },async (ctx) => { 
  ctx.body = { 
  code:0, 
  message:'pay success'  
  } 
  }); 
return app.serve(); 
};
小程序端 
 // 注册用户 
wx.cloud.callFunction({ 
  name:'user', 
  data: { 
  $url:'register', 
  name:'tcb', 
  password:'09876'  
  } 
  }).then((res) => { 
console.log(res); 
  }).catch((e) => { 
console.log(e); 
}); 
// 下单商品 
wx.cloud.callFunction({ 
  name:'pay', 
  data: { 
  $url:'makeOrder', 
  id:'xxxx', 
  amount:'3'  
  } 
  }).then((res) => { 
console.log(res); 
  }).catch((e) => { 
console.log(e); 
});
  架构三: 由一个云函数处理所有服务 
 云函数 
 // 函数 router  
const TcbRouter = require('tcb-router'); 
exports.main = async (event, context) => { 
const app = new TcbRouter({ event }); 
  app.router('user/register', async (ctx, next) => { 
await next(); 
  },async (ctx, next) => { 
await next(); 
  },async (ctx) => { 
  ctx.body = { 
  code:0, 
  message:'register success'  
  } 
  }); 
  app.router('user/login', async (ctx, next) => { 
await next(); 
  },async (ctx, next) => { 
await next(); 
  },async (ctx) => { 
  ctx.body = { 
  code:0, 
  message:'login success'  
  } 
  }); 
  app.router('pay/makeOrder', async (ctx, next) => { 
await next(); 
  },async (ctx, next) => { 
await next(); 
  },async (ctx) => { 
  ctx.body = { 
  code:0, 
  message:'make order success'  
  } 
  }); 
  app.router('pay/pay', async (ctx, next) => { 
await next(); 
  },async (ctx, next) => { 
await next(); 
  },async (ctx) => { 
  ctx.body = { 
  code:0, 
  message:'pay success'  
  } 
  }); 
return app.serve(); 
};
小程序端 
 // 注册用户 
wx.cloud.callFunction({ 
  name:'router', 
  data: { 
  $url:'user/register', 
  name:'tcb', 
  password:'09876'  
  } 
  }).then((res) => { 
console.log(res); 
  }).catch((e) => { 
console.log(e); 
}); 
// 下单商品 
wx.cloud.callFunction({ 
  name:'router', 
  data: { 
  $url:'pay/makeOrder', 
  id:'xxxx', 
  amount:'3'  
  } 
  }).then((res) => { 
console.log(res); 
  }).catch((e) => { 
console.log(e); 
});
借鉴 Koa2 的中间件机制实现云函数的路由管理 
  小程序·云开发的云函数目前更推荐async/await 的玩法来处理异步操作,因此这里也参考了同样是基于 async/await 的 Koa2 的中间件实现机制。 
  从上面的一些例子我们可以看出,主要是通过use 和 router 两种方法传入路由以及相关处理的中间件。 
use 只能传入一个中间件,路由也只能是字符串,通常用于 use 一些所有路由都得使用的中间件 
 // 不写路由表示该中间件应用于所有的路由  
app.use(async (ctx, next) => { 
}); 
app.use('router', async (ctx, next) => { 
});
  router 可以传一个或多个中间件,路由也可以传入一个或者多个。 
 app.router('router', async (ctx, next) => { 
}); 
app.router(['router', 'timer'], async (ctx, next) => { 
await next(); 
}, async (ctx, next) => { 
await next(); 
}, async (ctx, next) => { 
});
  不过,无论是use 还是 router,都只是将路由和中间件信息,通过 _addMiddleware 和 _addRoute 两个方法,录入到 _routerMiddlewares 该对象中,用于后续调用 serve 的时候,层层去执行中间件。 
  最重要的运行中间件逻辑,则是在serve 和 compose 两个方法里。 
  serve 里主要的作用是做路由的匹配以及将中间件组合好之后,通过 compose 进行下一步的操作。比如以下这段节选的代码,其实是将匹配到的路由的中间件,以及 * 这个通配路由的中间件合并到一起,最后依次执行。 
 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 的赋值,实现云函数的对小程序端的返回: 
 const fn = compose(middlewares);  
return new Promise((resolve, reject) => { 
  fn(this).then((res) => { 
  resolve(this.body);  
  }).catch(reject);  
});
  那么compose 是怎么组合好这些中间件的呢?这里截取部份代码进行分析 
 functioncompose(middleware)  { 
/** 
  * ... 其它代码 
  */ 
returnfunction (context, next)  { 
// 这里的 next,如果是在主流程里,一般 next 都是空。  
let index = -1; 
// 在这里开始处理处理第一个中间件  
return dispatch(0); 
// dispatch 是核心的方法,通过不断地调用 dispatch 来处理所有的中间件  
functiondispatch(i)  { 
if (i  { 
await next(); 
}
  而我们知道,dispatch 是返回一个 Promise.resolve 或者一个 Promise.reject,因此在 async function 里执行 await next(),就相当于触发下一个中间件的调用。 
当 compose 完成后,还是会返回一个 function (context, next),于是就走到下面这个逻辑,执行 fn 并传入上下文 this 后,再将在中间件中赋值的 this.bodyresolve 出来,最终就成为云函数数要返回的值。 
 const fn = compose(middlewares);  
return new Promise((resolve, reject) => { 
  fn(this).then((res) => { 
  resolve(this.body);  
  }).catch(reject);  
});
  看到Promise.resolve 一个 async function,许多人都会很困惑。其实撇除 next 这个往下调用中间件的逻辑,我们可以很好地将逻辑简化成下面这段示例: 
 let a = async () => { 
console.log(1); 
}; 
let b = async () => { 
console.log(2); 
return3; 
}; 
let fn = async () => { 
await a(); 
return b(); 
}; 
Promise.resolve(fn()).then((res) => { 
console.log(res); 
}); 
// 输出  
// 1  
// 2  
// 3 
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

客服热线
400-1234-888 周一至周日:09:00 - 21:00
公司地址:北京市朝阳区科技路88号现代城5号楼

新锐创想是一个融创意、设计、技术开发、服务为核心的新锐互联网公司,专注于Discuz!周边插件开发和精品模板设计,坚持为客户打造高品质的精品模板和插件。

Powered by Discuz!  X3.4 © 2013-2017 自学小程序开发社区   技术支持: 加田小店

Archiver|手机版|小黑屋|自学小程序开发社区

GMT+8, 2020-10-31 05:39 , Processed in 0.077376 second(s), 27 queries .

快速回复 返回顶部 返回列表