[博客小程序]公众号文章同步至云数据库实现

最近打算把我的博客小程序大改造一下,原因在于基于ghost的博客后台限制很多,另外我的那台服务器可能另做其他用途,可能不再维持我的博客网站了。

一些想法

首先想到的是博客小程序可以完全脱离服务端「不需要后端,域名,服务器,备案等」。可以基于小程序提供的云开发功能来实现整个博客小程序的所有功能。

这样减少了很多后端依赖,也方便很多读者搭建属于自己的小程序,毕竟目前我现有的小程序还完全依赖ghost的开源博客。

但文章的数据源从哪里获取呢?毕竟博客小程序最终的还是文章内容。目前考虑的是github和微信公众号,可以将这两个地方作为自己文章的数据源,然后通过功能来实现同步相应的文章。

由于自己本身有个公众号,平时文章也会发布到公众号上,所以目前打算将公众号的文章作为我的文章数据源,来实现我的新版博客小程序。

确认可操作性

既然决定公众号的文章作为数据源,那么就开始验证下可操作性「毕竟公众号还是有很多限制的,尤其是个人号」。

首先确认是否有相应的接口权限,这里主要用到获取素材相关的接口,可以看到对应接口文档,个人号还是有对应权限的「还好,如果这个都没有,这个方案就可以直接pass了」

文档截图1

其次是调用前权限配置问题,在查看文档后,公众号获取token需要添加IP白名单

文档截图2

这个就有点坑爹了,所有后端功能完全基于小程序云开发,而小程序的云函数所对应的IP显然是不固定的,这叫我如何配置。

在google了N久之后发现,还是有很多小伙伴遇到此类问题的,一种是采用代理的方式「还是需要依赖后端服务器」。另一种是穷举,有小伙伴实践过,基本上云函数对应的IP就如下几个,全部配置到白名单中即可。

172.81.207.12
172.81.212.74
172.81.235.12
172.81.236.99
172.81.245.51
212.64.65.131
212.64.84.22
212.64.85.139
212.64.85.35
212.64.87.134
212.64.57.239
212.64.68.233
212.64.84.102
212.64.84.30
212.64.84.54
212.64.85.82
212.64.89.109
212.64.89.115
212.64.89.17
212.64.89.18

解决了这两个问题之后,利用云函数同步公众号文章至云数据库应该是可以实现的。

具体实现

实现的逻辑还是比较简单的,具体分三个步骤:

  1. 获取公众号的access_token(不是小程序的)
  2. 遍历调用公众号永久素材列表接口获取数据
  3. 将文章相关数据保存至云数据库中

首先获取access_token就不多说了,在写评论推送功能实现的文章中已经提过。直接上代码:

/**
 * 获取公众号token
 * @param {}  
 */
async function getAccessWechatToken() {
  const result = await rp({
    url: `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appId=${APPID}&secret=${APPSCREAT}`,
    method: 'GET'
  });

  //TODO:需要验证IP白名单失效问题(ip改变导致无法获取到token)
  console.info(result)
  let rbody = (typeof result === 'object') ? result : JSON.parse(result);
  return rbody;
}

然后调用素材列表接口,获取相应的文章信息,这里主要获取公众号的图文信息(type为news)

/**
 * 获取公众号文章信息
 * @param {*} accessToken
 */
async function getWechatPosts(accessToken, offset, count) {
  let url = `https://api.weixin.qq.com/cgi-bin/material/batchget_material?access_token=${accessToken}`
  var options = {
    method: 'POST',
    json: true,
    uri: url,
    body: {
      "type": "news",
      "offset": offset,
      "count": count
    }
  }
  const result = await rp(options)
  let rbody = (typeof result === 'object') ? result : JSON.parse(result);
  return rbody;
}

最后将获取到的图文信息保存到云数据库中,逻辑比较简单,就不多说了,直接上代码。

/**
 * 同步公众号文章至云数据库
 */
async function syncWechatPosts(isUpdate) {
  let collection = "mini_posts"
  let accessToken = await getCacheAccessToken(1)
  var offset = 0
  var count = 10
  var isContinue = true
  while (isContinue) {
    var posts = await getWechatPosts(accessToken, offset, count)
    if (posts.item.length == 0) {
      isContinue = false
      break;
    }

    for (var index in posts.item) {
      //判断是否存在
      let existPost = await db.collection(collection).where(
        {
          uniqueId: posts.item[index].media_id,
          sourceFrom: "wechat"
        }).get();

      if (existPost.code) {
        continue;
      }
      if (!existPost.data.length) {

        var data = {
          uniqueId: posts.item[index].media_id,
          sourceFrom: "wechat",
          content: posts.item[index].content.news_item[0].content,
          author: posts.item[index].content.news_item[0].author,
          title: posts.item[index].content.news_item[0].title,
          defaultImageUrl: posts.item[index].content.news_item[0].thumb_url,
          createTime: posts.item[index].update_time,
          totalComments: 0,//总的点评数
          totalVisits: 100,//总的访问数
          totalZans: 50,//总的点赞数
          label: [],//标签
          classify: 0,//分类
          contentTyep:"html"
        }

        await db.collection(collection).add({
          data: data
        });
      }
      else {
        //不需要更新直接继续
        if (!isUpdate) {
          continue
        }

        let id = existPost.data[0]._id;
        await db.collection(collection).doc(id).set({
          data: {
            content: posts.item[index].content.news_item[0].content,
            author: posts.item[index].content.news_item[0].author,
            title: posts.item[index].content.news_item[0].title,
            defaultImageUrl: posts.item[index].content.news_item[0].thumb_url,
            createTime: posts.item[index].update_time
          }
        });

      }
    }

    offset=offset+count
  }
}

到这里,公众号的文章就顺利同步到了小程序的云数据库中了,后面小程序渲染的数据源就可以直接从云数据库中取了。

当然你也可以举一反三,数据源不一定通过公众号,也可以通过github或者其他途径,统一同步到小程序的云数据库中,这样你的博客小程序就可以完全独立了。

云后台截图

总结

目前完全脱离ghost开源博客的小程序还在开发中,等有一些进展之后会开源出来,有兴趣的可以关注下。

作者:玄冰
欢迎关注我的微信公众号和博客小程序
欢迎关注我的公众号 欢迎关注我的公众号