微信云开发小试牛刀

416 阅读4分钟

云环境搭建

项目初始化

使用框架mpx(类vue语法开发小程序的框架)

## 全局安装脚手架
npm i -g @mpxjs/cli
## 初始化项目
mpx create mpx-cloud-function-demo

选择云函数相关的配置

mpx云函数说明:mpxjs.cn/guide/advan…

配置云函数文件目录并暴露main函数

配置云函数和小程序的指定目录

image.png

生成的小程序的代码和云函数的代码均需要再project.config.json中指明,才能被微信开发平台的对指定目录的读取

暴露main函数

const application = require('./framework/core/application.js')

exports.main = async (event, context) => {
  return await application.app(event, context)
}

在云函数的的出口文件index.js中暴露main方法(因为是node环境,所以使用export方法),此处,我是将index.js仅仅作为暴露的出口,将核心逻辑写在application.js的方法中(具体代码如下:)

const cloudBase = require('../cloud/cloud_base.js')
const appUtil = require('./app_util.js')
const routes = require('../../config/route.js')
const config = require('../../config/config.js')
const dayjs = require('dayjs')

const splitLine = '▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦'

async function app(event) {
  const cloud = cloudBase.getCloud()
  const wxContext = cloud.getWXContext()
  let r = ''
  try {
    // note: 错误排查,如果没有路由,可以理解为https的url
    if (!event.route) {
      console.error(`Route Not Defined: ${event}`)
      return appUtil.handlerSvrErr()
    }

    r = event.route.toLowerCase()
    // note: 如果没有/需要直接报错
    if (!r.includes('/')) {
      console.error(`Route Format error[${r}]: ${event}`)
      return appUtil.handlerSvrErr()
    }

    // note: 如果没有得到配置的对应value值
    if (!routes[r]) {
      console.error(`Route [${r}] Is Not Exist: ${event}`)
      return appUtil.handlerSvrErr()
    }

    // note: 进入正常的逻辑处理中去,根据云函数的请求来获取具体的模块,用配置的路由的value值去做相关的请求处理,使用@将controller层和每一层的执行方法定义出来
    const routesArr = routes[r].split('@')
    let [controllerName, actionName] = routesArr

    const time = dayjs().format('YYYY/MM/DD HH:mm:ss')
    const timeTicks = dayjs().valueOf()

    const openId = wxContext.OPENID

    // note: 将controller层和执行模块进行记录,以及用户的openid收集
    console.log(splitLine)
    console.log(`time: ${time} \n ENV: ${config.CLOUD_ID} \n Controller: ${controllerName}\n Action: ${actionName}\n OPENID: ${openId}`)

    // note: 引入对应模块的逻辑controller的名称
    controllerName = controllerName.toLowerCase().trim()
    // note: 获取相关的controller并实例化
    const ControllerClass = require(`project/controller/${controllerName}.js`)
    const controller = new ControllerClass(r, openId, event)

    // note: 初始化接口逻辑处理
    if (controller && controller.initSetUp) {
      await controller.initSetUp()
    }
    let result = await controller[actionName]()

    // note: 返回值处理,判断是否需要包装成小程序的规范处理
    if (isOther) {
      return result
    } else {
      result = result ? appUtil.handlerData(result, r) : appUtil.handlerSucc(r)
    }
    // note: 记录每个接口调用耗时和具体请求和响应的时间
    const endTime = dayjs().format('YYYY/MM/DD HH:mm:ss')
    const endTimeTicks = dayjs().valueOf() - timeTicks
    console.log(`endTime: ${endTime} \n endTimeTicks: ${endTimeTicks}`, result)
    console.log(splitLine)
    return result
  } catch (ex) {
    const log = cloud.logger()
    const time = dayjs().format('YYYY/MM/DD HH:mm:ss')
    console.error(`time: ${time} \n MSG: ${ex.message} \n CODE: ${ex.code}`)
    // node: 系统级错误定位调试
    if (ex.name !== 'AppError') throw ex
    console.log(splitLine)
    if (ex.name === 'AppError') {
      log.warn({
        route: r,
        errCode: ex.code,
        errMsg: ex.message
      })
      return appUtil.handlerAppErr(ex.message, ex.code)
    } else {
      log.error({
        route: r,
        errCode: ex.code,
        errMsg: ex.message,
        errStack: ex.stack
      })
      return appUtil.handlerSvrErr(ex)
    }
  }
}

module.exports = {
  app
}

小坑:此处遇到过一个问题:在本地调试和正式环境的表现不一致,其原因是本地的node版本和正式环境的node版本不一致

云函数导出说明:developers.weixin.qq.com/miniprogram…

上传函数并新建函数

上传云函数到微信云开发平台

image.png

选择模块example上传到云端

如果目录下存在package.json,云端自动检测并安装相关依赖

在云开发平台创建对应的云函数

image.png

注意这个地方云函数名称要与上传时候的模块的目录名称一样

实现数据的crud

初始化云函数配置

const config = require('../../config/config.js')
const getCloud = () => {
  const cloud = require('wx-server-sdk')
  cloud.init({
    env: config.CLOUD_ID // note: 下图对应的环境ID
  })
  return cloud
}
module.exports = {
  getCloud
}

image.png

不同层的数据处理及数据流向

分层调用

云函数开发.png

比较通用的后端分层

数据库调用

数据连接及修改

const cloudBase = require('../cloud/cloud_base.js')
const cloud = cloudBase.getCloud()
const db = cloud.database()

const collectionName = 'demo_test_data'
// note: 添加数据
db.collection(collectionName).add({
   data
 })

// note: 删除数据
db.collection(collectionName).where({
  filed: ''
}).remove()

// note: 更新数据
db.collection(collectionName).where({
  filed: ''
}).update({
  data
})

// note: 数据查询
db.collection(collectionName).get()

详细调用查看:developers.weixin.qq.com/miniprogram…

关系型文档型
数据库 database数据库 database
表 table集合 collection
行 row记录 record / doc
列 column字段 field

云开发提供的json库本质就是MongoDB的文档型数据库,均为非关系型数据库

文件上传

  async uploadImg() {
      const chooseResult = await wx.chooseImage()
      if (chooseResult?.tempFilePaths?.length) {
        const res = await wx.cloud.uploadFile({
          cloudPath: guid(),
          filePath: chooseResult.tempFilePaths[0]
        })
        if (res?.fileID) {
          await this.callFunction({
            route: 'demo/filenameupload',
            params: {
              fileID: res.fileID
            }
          })
          this.getImgList()
        }
      }
    },
  callFunction({ route = 'demo/filelist', params = {} } = {}) {
      return new Promise((resolve, reject) => {
        wx.cloud.callFunction({
          name: 'example', // note: 想要调用对应的模块名称
          data: { // note: 上传的值,对应到云函数侧可以被event取到其所有值
            route,
            params
          }
        }).then(res => {
          resolve(res.result)
        }).catch(err => {
          reject(err)
        })
      })
    }

前端调用

云函数调用初始化

wx.cloud.init({
  env: 'env-id',
  traceUser: true
})

一般在app.mpx中完成

调用数据示例

  callFunction({ route = 'demo/get', params = {} } = {}) {
      return new Promise((resolve, reject) => {
        wx.cloud.callFunction({
          name: 'example', // note: 想要调用对应的模块名称
          data: { // note: 上传的值,对应到云函数侧可以被event取到其所有值
            route,
            params
          }
        }).then(res => {
          resolve(res.result)
        }).catch(err => {
          reject(err)
        })
      })
    }

总结

demo完成过程中遇到的问题

  • 本地调试和线上的node版本不一致问题

云开发的优劣

优势(特点)

  • 坡度小:无需搭建服务器和数据库,开发体验对前端极其友好
  • 高效便捷:在微信体系内的鉴权简单,获取微信相关信息容易
  • 成本低:开发成本和维护成本都比较低,上线也十分方便

不足

  • 数据读取慢:数据调用的速度略慢,详细的数据对比还需数据统计(可能是买的套餐问题导致)
  • 无法友好的处理数据量大的情况
  • 无法友好打通微信生态和非微信应用之间的数据交互(虽然现在官方已经可以提供web sdk,但调用起来并没有http那么方便

云开发的使用场景

适用场景

  • 制作demo:产品原型阶段能力调用测试
  • 小型应用:预约系统
  • 个人创业小项目:配置较少,核心功能较少,微信端的应用
  • 毕业设计,完整的数据流,且需要的时间很少,学习成本也相对较小

不建议使用场景

  • 强依赖后台配置的应用
  • 大型应用
  • 需要跨端的应用

基于以上优劣,个人不建议单独花费大量时间去学习

todelist

  • 消息推送(需要验证token的服务器)
  • 支付相关(需要企业商户、个体经商户)
  • 云开发数据库与web应用的调用问题(调研实现方式)
  • 日志收集能力(方便排错)

demo视觉

gh_826280291e4d_258.jpg

备注:可主要关注数据效果,前端效果暂时没优化