• 实战 | 打造一个双端自动发布的博客体系(下)


    项目背景

    上期文章主要介绍了博客项目的背景、技术选型、开发框架和系统设计部分的内容,承接上期,下文主要介绍该小程序的登录方式配置、分享订阅消息功能是如何实现的。

    云开发控制台入口:https://console.cloud.tencent.com/tcb

    云开发CloudBase 是什么

    云开发(Tencent CloudBase,TCB)是腾讯云提供的云原生一体化开发环境和工具平台,为开发者提供高可用、自动弹性扩缩的后端云服务,包含计算、存储、托管等serverless化能力,可用于云端一体化开发多种端应用(小程序,公众号,Web 应用,Flutter 客户端等),帮助开发者统一构建和管理后端服务和云资源,避免了应用开发过程中繁琐的服务器搭建及运维,开发者可以专注于业务逻辑的实现,开发门槛更低,效率更高。

    系统实现

    1 数据库

    文章:

    sync_posts = [
      {
        _id: String,
        createTime: String,
        slug: String,
        title: String,
        tags: Array,
        description: String,
        cover: String, // url
        content: String, // html
      }
    ]
    // 安全规则
    {
      "read": true, // 公有读
      "write": "get('database.user_info.${auth.openid}').isManager", // 仅管理员可以写
    }
    

    用户收藏:

    user_favorite = [
      {
        _id:String,
        userId:String,// openid
        postId: String,// 在表中加入冗余数据直接查询
        createTime: Date
      }
    ]
    // 安全规则
    {
      "read": "doc._openid == auth.openid",// 私有读
      "write": "doc._openid == auth.openid"// 私有写
    }
    

    用户信息:

    user_info = [
      {
        _id: String,
        _openid: String,
        ...userInfo,
        isManager: Boolean,
      }
    ]
    // 安全规则
    {
      "read": "doc._openid == auth.openid", // 私有读
      "write": "doc._openid == auth.openid"// 私有写
    }
    

    2 登录

    2.1 普通登录

    使用云开发后,无需通过wx.login获取登录凭证(code)进而换取用户登录态信息,因为每次调用云函数时已经附带调用者 openid。

    由于可以直接通过 open-data 展示用户信息(不论是否授权),一些小程序因此绕过用户登录;有些小程序通过授权用户信息后保存到数据库,后续操作均使用数据库信息,无法在用户变更信息后更新;如果用户主动通过设置页取消授权,但返回后却还在展示使用用户的信息(显示已登录),这是因为用户态信息是通过 onLoad 获取的,返回操作时是 onShow,故此时会产生矛盾;用户在重新授权登录时选择使用其他昵称和头像,这时一些小程序会认为是新用户登录;还有一部分小程序不论业务中是否需要用户信息,均要求授权才可使用。

    基于"来去自如"[1]的原则,可以游客身份浏览,但在涉及一些需要采集和输入用户信息、或保存用户记录的功能时会要求,用户跳至登录页授权获取信息,通过云函数将其与上下文中的 openid 保存到数据库,同时在回调中将用户标识生成自定义登录态缓存到本地,如果用户点击退出会将其置空。

    // cloudfunction/login
    const openid = wxContext.OPENID
    db.collection('user_info').where({
      _openid: openid
    }).get().then(async (res)=> {
      if (res.data.length === 0) {
        db.collection('user_info').add({
          data: {
            _openid: openid,
            ...event.userInfo,
            createTime: db.serverDate(),
          }
        })
      }
    

    在下次打开小程序时,会通过检查缓存中的自定义登录态来判断用户是否登录,同样调用云函数来更新用户信息和使用信息(如打开时间、打开次数用于后续用户分析)。如果在onShow中监测,会与正常onLaunch产生重复的逻辑。实际上,打开设置页必然会进入onHide,可按如下方式监测:

    // app.js
    onHide:function() {
      wx.onAppShow(()=> {
        if(this.globalData.hasLogin) {
          wx.getSetting({
            success: res => {
              if (!res.authSetting['scope.userInfo']) { // 取消了授权
                this.logout() // 返回后直接登出
              }
            }
          })
        }
        wx.offAppShow();
      })
    },
    

    2.2 管理员鉴权

    管理员即文章作者,对于管理员标识,考虑到:

    • 手机号: 目前该接口针对非个人开发者,且完成了认证的小程序开放;
    • openid: 不使用前是未知的,无法提前绑定;
    • 用户信息是可变的不可绑定;
    • 密码方式会暴露管理入口。

    于是暂时采取了最简单直接的数据字段标记isMaganer:true,这一字段也会用于数据库的安全规则设定。

    3 分享

    分享形式无非两种:直接分享到聊天和生成海报后引导分享到朋友圈。

    对于前者,需要考虑图片大小为5:4,其他比例会产生空白或者裁切。这里主要主要分析后者。在小程序端通过 canvas 绘制导出图片比较慢,由于每篇文章分享内容基本固定,可以考虑预生成。但如果分享二维码和分享者关联,就仍然需要本地生成。这里使用组件 mini-share。对于小程序码,目前采用云调用方式,这种方式只能从小程序端触发,故不能预生成。

    // 处理参数
    const path = page +'?' + Object.keys(param).map(function (key) {
        return encodeURIComponent(key) + "=" + encodeURIComponent(param[key]);
    }).join("&");
    // 组织文件名
    const fileName = 'wxacode/limitA-' + crypto.createHash('md5').update(path).digest('hex');
    // 查找文件,如果找到直接返回路径
    let getFileRes = await cloud.getTempFileURL({
      fileList: [fileID]
    });
    // 若未找到重新生成
    const wxacodeRes = await cloud.openapi.wxacode.get({
      path,
      isHyaline:true
    })
    // 上传到云存储
    const uploadRes = await cloud.uploadFile({
      cloudPath: fileName + fileSuffix,
      fileContent: wxacodeRes.buffer,
    });
    // 获取返回临时路径
    getFileRes = await cloud.getTempFileURL({
      fileList: [uploadRes.fileID]
    });
    

    生成二维码方式的特性可归纳为:

    img

    这里由于文章的数据库_id默认是32位,达到了B类的限制,并且还需要关联其他信息,故使用了A类(wxacode.get)。

    4 订阅消息

    对于个人主体,只能用户经小程序发起订阅(获取下发权限)后下发一次消息,这里当用户留言时,会订阅一次回复通知,但无法发给作者(除非作者长期订阅)。由于同时需要保存到数据库,这里采用云调用实现。

    // post.js
    wx.requestSubscribeMessage({
      tmplIds: [TEMPLATE.REPLY]
    })
    // cloudfunction/sengMsg
    let sendRes = await db.collection('user_msg').add({
      data: {
        _openid: wxContext.OPENID,
        msg:inputMsg,
        createTime:Date.parse(new Date())
      }
    });
    await cloud.openapi.subscribeMessage.send({
      data: format(data), // 由于各种类型信息有长度格式限制,需要处理
      touser: wxContext.OPENID,
      templateId: TEMPLATE.REPLY
    });
    

    5 开源

    开源地址:作者整理中,将会上传于github.com/makergyt,敬请关注。

    静态站点:blog.makergyt.com

    备用链接:github.blog.makergyt.com

    小程序:「源创智造」,其中接入了一些工具。

    参考资料:

    [1]: Tencent.微信小程序设计指南https://developers.weixin.qq.com/miniprogram/design/. 2019

  • 相关阅读:
    14. D3D光照
    17. 增加对硬件光照的支持
    ECommerce Starter Kit 数据库表和存储过程一览
    使用 DataAdapter 执行批量更新
    学习Professional ASP.NET 2.0(四)
    c#泛型学习(二)
    学习Professional ASP.NET 2.0(一)
    学习Professional ASP.NET 2.0(二)
    下载:微软网页设计工具CTP测试版(支持asp.net2.0)
    学习ECommerce Starter Kit (1)
  • 原文地址:https://www.cnblogs.com/CloudBase/p/13540884.html
Copyright © 2020-2023  润新知