0.0.6 • Published 2 years ago

@tmsfe/tms-cloud-sdk v0.0.6

Weekly downloads
-
License
ISC
Repository
-
Last release
2 years ago

@tmsfe/tms-cloud-sdk

TOC


Thoughts

云开发提供了完整的一套服务端能力,可以让我们快速开发服务端业务逻辑而不用关注运维部署的细节。在过往的项目中,已经有一些典型的应用场景。

但是在云函数的开发和发布环节,还是有不少痛点,tms-cloud-sdk致力于解决云函数开发环节的痛点。部署环节的痛点另行方案解决,不在此讨论。

下面列举大家日常云开发联调过程中反馈的问题。我们围绕这些问题来封装公共能力。


重复且模板化的云函数框架初始代码

在每个云函数初始化时,都会存在类似的代码:

const TcbRouter = require('tcb-router');
const cloud = require('wx-server-sdk');

cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV });
const getWxContext = () => {
  const wxContext = cloud.getWXContext();

  return {
    openId: wxContext.OPENID,
    appId: wxContext.APPID,
    unionId: wxContext.UNIONID,
  };
};

// 云函数入口函数
exports.main = async (event) => {
  const app = new TcbRouter({ event });
  app.use(async (ctx, next) => {
    // 统一参数处理
    const { openId } = cloud.getWXContext()();
    const { event } = ctx._req; // eslint-disable-line
    Object.assign(ctx, { data: {
      openId,
      ...event,
    } });
    try {
      const resData = await next();
      Object.assign(ctx, { body: { errCode: 0, errMsg: 'success', resData } });
    } catch (e) {
      // 统一异常处理
      const { errCode, errMsg } = e;
      Object.assign(ctx, { body: { errCode, errMsg, resData: null } });
    }
  });

  app.router('xxx/xxx', () => {}); // 路由注册
  return app.serve();
};

分析这段代码,不同云函数之间有差异的只是路由注册的部分,参数预处理的中间件完全可以复用。

我们也有必要统一所有云函数的基础中间件,以实现日志打印的标准化;之前遇到部分云函数日志打印不全,需要排查时无从查起的尴尬场面;如果我们将日志打印标准化在基础中间件里,就可以避免此类问题。


海报图开发调试效率低下

很多时候我们需要绘制一张动态的还报图片,有很多云函数有写过这个逻辑,现在也有一个 canvasImg 的云函数来画图;其思路是在Node端用canvas画图,然后将canvas保存成图片。这种实现思路,开发联调的效率必然不高。

我们没有现成的可视化canvas画图工具,只能边改边发布云函数来调试,且此方案依赖的node-canvas包,在云函数环境无法正常安装,本地和云端需要兼容不同的node_modules依赖,见云函数中特殊npm包的分层解决方案

换个思路,如果我们不去画canvas,而是去写HTML页面,这样本地就可以快速完成复杂视觉的HTML开发,云函数要做的只是将这个HTML渲染,保存成图片即可。且云函数环境已默认集成 puppeteer 包,不存在依赖安装问题。

按照这个思路,我们在tms-cloud-sdk中封装了画图的公共方法,拿来即用。


生成小程序码还要依赖后端

云函数中可以免鉴权调用微信的开放接口,直接生成小程序码,在一些业务场景需要生成动态小程序码让用户分享,前端可自己完成。

我们在tms-cloud-sdk中封装了生成小程序码的接口,在微信开放能力的基础上做了扩展,支持上传到云存储或转base64,方便大家拿来即用。


内容安全检测不能拿来即用

云函数中可以免鉴权调用微信的内容安全检测接口,但接口需要传很多定制参数,需要了解上下文背景。我们对这个接口做了一层封装,使用时只需传要检测的内容即可。


Documentation

serve 云函数初始化

serve方法是tms-cloud-sdk提供的云函数入口高阶函数,业务只需传入路由表和自定义中间件即可。serve方法中封装了统一的参数预处理,包括对不同调用方(小程序端、定时任务、微信回调、HTTP访问)的入参标准化。

同时,serve方法统一增加了云函数出入参的日志打印中间件。


参数

Object routes

路由表,Object类型,key为路由路径,value为处理函数

Array middleware

自定义中间件,Array类型,每一项为独立中间件函数


返回值

Function fn

返回云函数入口函数,可以直接用于云函数初始化。


示例代码

const tmsCloud = require('@tmsfe/tms-cloud-sdk');

const routes = {
  'testfn/testroute': (ctx) => console.log(ctx),
};

const middleware = [async (ctx, next) => {
  tmsCloud.logger.info(ctx);
  return await next();
}];

exports.main = tmsCloud.serve(routes, middleware);

html2img 将HTML渲染为图片

顾名思义,将html渲染成图片,适用于动态生成海报图、分享图等业务场景。

此方法是对 puppeteer 的二次封装,拓展了对图片文件的处理,可以拿来即用。


性能优化提示:

云函数运行时环境内置了 puppeteer, 我们的实现思路是用 puppeteerheadless 模式下打开要绘制的html页面,然后调用 screenshot 方法截图。

在这个过程中,初始化 puppeteer 实例需要时间,加载html页面需要时间,截图也需要时间,尤其是加载html页面,这个过程的耗时取决于html中加载的资源体量。如果在页面中使用了大量网络资源(图片、css)等时,加载耗时会明显增加。

因此建议在html中严格控制使用的网络资源,尽可能用 base64 的方式嵌入在html中。

在绘制图片时,难免会用到一些特殊字体,我们已经将常用的字体以css文件的形式存放在cdn上,在html中可以直接用link标签引用。 如有其他字体包定制需求,请参照下面的base64字体css文件,或联系petegao协助处理。

<!--腾讯体W3-->
<link rel="stylesheet" href="https://static.img.tai.qq.com/web/fonts/TencentSans-W3.css">
<!--腾讯体W7-->
<link rel="stylesheet" href="https://static.img.tai.qq.com/web/fonts/TencentSans-W3.css">
<!--苹果平方标准体-->
<link rel="stylesheet" href="https://static.img.tai.qq.com/web/fonts/PingFang-Normal.css">
<!--DIN-Alternate-->
<link rel="stylesheet" href="https://static.img.tai.qq.com/web/fonts/DIN-Alternate.css">

参数

Object options

绘图配置

属性类型默认值必填说明
outputstring生成图片的云函数本地路径,只需指定目录路径,文件名自动生成;为空时不保存本地文件
cloudOutputstring生成图片的云存储路径,只需指定云存储目录路径,文件名自动生成;为空时不存储
htmlstring要渲染的html内容,支持本地html文件路径、云存储fileID、网络https文件路径、或直接传html字符串
contentstringhandlebars模板内容,传入后将把html视为handlebars模板来渲染
transparentbooleanfalse绘制的图片是否透明背景
encodingstringbinary绘制图片的编码格式,支持 binary/base64, 默认为binary
selectorstringbody要绘制的元素,默认是body,可以通过css选择器标识要绘制的元素
typestringpng生成图片的文件类型,jpeg/png,默认为png

返回值

Object rsp

属性类型说明
localPathstring生成图片的云函数本地路径,入参传入output时有效
fileContentbinary/base64生成的图片内容,内容格式为binary/base64,取决于入参的encoding
encodingstring与入参的encoding相同
fileIDstring云存储文件ID,当入参传cloudOutput时有效
tempFileURLstring云存储文件http访问链接,当入参传cloudOutput时有效

示例代码

const tmsCloud = require('@tmsfe/tms-cloud-sdk');

const routes = {
  'testfn/drawimg': async () => {
    const html = `
      <!DOCTYPE html>
      <html>
      <head>
      <style>
      #myHeader {
        background-color: lightblue;
        color: black;
        padding: 40px;
        text-align: center;
      } 
      </style>
      </head>
      <body>

      <h2>{{title}}</h2>
      <p>{{desc}}</p>

      <h1 id="myHeader">My Header</h1>

      </body>
      </html>
    `;
    const { tempFileURL } = await tmsCloud.html2img({
      html,
      content: {
        title: 'Yehuda',
        desc: 'Katz',
      }
      cloudOutput: 'testfn/',
    });
    return { tempFileURL };
  },
};

exports.main = tmsCloud.serve(routes);

callSinanServer 在云函数中调用SinanServer

在云函数中以L5的方式调用接入层SinanServer。

注意调用此方法的云函数必须是由微信环境(小程序调用/定时任务调用)触发,否则会提示微信cloudApiToken错误。


参数

String path

要请求的接口路径

Object param

要携带的参数,注意必须携带userId、token、wxAppId、seqId这几个公共参数,这些参数小程序里通过 tms.callCloudFunc 调用云函数时都有,直接透传即可。

String method

请求方法,支持 get/post

String env

请求的SinanServer环境,支持 test/production,分别对应SinanServer测试/生产环境


返回值

Object rsp

属性类型说明
errCodestring接口错误码
errMsgstring接口错误信息描述
resDataobject业务数据

示例代码

const tmsCloud = require('@tmsfe/tms-cloud-sdk');

const routes = {
  'testfn/callsinan': async (ctx) => {
    const { userId, token, seqId, wxAppId } = ctx.event;
    const res = await tmsCloud.callSinanServer(
      'user/carlist',
      { userId, token, seqId, wxAppId },
      'post',
      'production'
    );
    return res;
  },
};

exports.main = tmsCloud.serve(routes);

getAppCode 生成小程序码

在云函数中生成小程序码。

此方法是对微信开放能力 cloud.openapi.wxacode.getUnlimited 的二次封装,拓展了对小程序码图片文件的处理,可以拿来即用。

注意调用此方法的云函数必须是由微信环境(小程序调用/定时任务调用)触发,否则会提示微信cloudApiToken错误。


参数

Object config

生成小程序码的配置

属性类型默认值必填说明
pagestring页面 page,例如 pages/index/index,根路径前不要填加 /,不能携带参数(参数请放在scene字段里),如果不填写这个字段,默认跳主页面
scenestringquery参数,会拼在page后,在扫码打开的页面onLoad可以拿到。最大32个可见字符,只支持数字,大小写英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~,其它字符请自行编码为合法字符(因不支持%,中文无法使用 urlencode 处理,请使用其他编码方式)
checkPathbooleantrue检查 page 是否存在,为 true 时 page 必须是已经发布的小程序存在的页面(否则报错);为 false 时允许小程序未发布或者 page 不存在, 但 page 有数量上限(60000个)请勿滥用
envVersionstringrelease要打开的小程序版本。正式版为 release,体验版为 trial,开发版为 develop
widthnumber二维码的宽度,单位 px,最小 280px,最大 1280px
autoColorboolean自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调,默认 false
lineColorobjectautoColor 为 false 时生效,使用 rgb 设置颜色 例如 {"r":"xxx","g":"xxx","b":"xxx"} 十进制表示
isHyalinebooleanfalse是否需要透明底色,为 true 时,生成透明底色的小程序
saveToCloudbooleanfalse是否包存到云存储,默认false,传true时将自动上传至云存储,并返回文件ID与http访问链接

返回值

Object rsp

属性类型说明
contentTypestring小程序码图片类型,png/jpeg
bufferbuffer小程序码图片文件流
string64string小程序码base64字符串,可直接用于 image 标签 src 展示
fileIDstring云存储文件ID,当入参saveToCloud为true时有效,可直接用于 image 标签 src 展示
tempFileURLstring云存储文件http访问链接

示例代码

const tmsCloud = require('@tmsfe/tms-cloud-sdk');

const routes = {
  'testfn/wxacode': async () => {
    const { tempFileURL, fileID, string64 } = await tmsCloud.getAppCode({
      page: 'modules/car/index/index',
      scene: 'wecarId=xxxx',
      checkPath: true,
      envVersion: 'release',
      saveToCloud: true,
    });
    return { tempFileURL, fileID, string64 };
  },
};

exports.main = tmsCloud.serve(routes);

msgSecCheck 文本内容安全检测

检查一段文本是否含有违法违规内容。

此方法是对 cloud.openapi.security.msgSecCheck 的封装,简化了调用参数。

注意调用此方法的云函数必须是由微信环境(小程序调用/定时任务调用)触发,否则会提示微信cloudApiToken错误。


参数

String openid

用户的openid,可以从云函数请求上下文中获取

String content

需检测的文本内容,文本字数的上限为2500字,需使用UTF-8编码


返回值

Object result

属性类型说明
labelnumber命中标签枚举值,100 正常;10001 广告;20001 时政;20002 色情;20003 辱骂;20006 违法犯罪;20008 欺诈;20012 低俗;20013 版权;21000 其他
suggeststring建议,有risky、pass、review三种值

示例代码

const tmsCloud = require('@tmsfe/tms-cloud-sdk');

const routes = {
  'testfn/msgcheck': async (ctx) => {
    const { OPENID } = ctx.wx_context;
    const { label, suggest } = await tmsCloud.msgSecCheck(OPENID, 'xxxxx');
    return { label, suggest };
  },
};

exports.main = tmsCloud.serve(routes);

cloud

require('@tmsfe/tms-cloud-sdk').cloud

等价于

require('wx-server-sdk').cloud

logger

require('@tmsfe/tms-cloud-sdk').logger

等价于

require('wx-server-sdk').cloud.logger()

Contributing

在日常云开发过程中,肯定还有很多痛点,大家有想法欢迎随时提出需求,当然如果大家能协同共建,贡献代码,自然是最好的。

0.0.6

2 years ago

0.0.5

2 years ago

0.0.4

2 years ago

0.0.3

2 years ago

0.0.2

2 years ago