Hexo去LeanCloud依赖

7.19日,收到了LeanCloud的邮件,大意如下:

8 月 1 日起,LeanCloud 国际版共享域名不再向中国大陆提供服务

为履行合规责任,降低平台风险,LeanCloud 国际版共享域名将于 2022 年 8 月 1 日起不再向中国大陆的最终用户提供服务,国际版共享域名仅服务于海外用户。

静态网站的状态存取是个痛点。好消息是本站使用Hexo NexT主题,天然集成了文章阅读量的功能,后端存储是LeanCloud,仅需配置app_idapp_key。而评论系统是另一个坑,一年前 切换到了Waline,一举攻克了这个难题,但当时Waline也依赖于LeanCloud。

这次LeanCloud国际版共享域名不向中国大陆提供服务改动,对Waline无影响,因为Waline的前端部署在Vercel海外节点。但如果网站面向大陆用户,文章阅读量统计会受影响。

因此,考虑将本站去LeanCloud依赖。方法很简单,将文章阅读量切换至Waline,同时Waline的后端存储改用MongoDB。去依赖需要你有一台服务器,自建MongoDB,或者直接使用 MongoDB Atlas的免费版

使用MongoDB存储数据的好处:

  • 速度更快,LeanCloud访问速度一言难尽
  • 数据自己存储,非常灵活,方便导入导出
  • 去除LeanCloud API存储依赖(引入MongoDB依赖 :-) )

切换Waline后端存储

看起来很简单,参考 # 多数据库服务支持 。实际操作还是踩了不少坑,主要痛点是已有数据的导出和导入。

切换存储很简单,仅需改变下Vercel前端的环境变量,并重新部署令其生效。保险起见,强烈建议新建项目,方便导出导入数据。方便描述,两个Vercel app用OldAppNewApp进行指代。

先在NewApp配置如下MongoDB的相关环境变量:

Vercel MongoDB Environment Variables Setting

值得一提的是MONGO_HOSTMONGO_PORT的设置,是两个List:

MONGO_HOST=["cluster0-shard-00-00.p4edw.mongodb.net","cluster0-shard-00-01.p4edw.mongodb.net","cluster0-shard-00-02.p4edw.mongodb.net"]
MONGO_PORT=[27017,27017,27017,27017]

个人觉得此配置有些过度设计,这么多参数,仅需一个参数替代:MongoDB连接串。

改完环境变量,理论上后端已经从LeanCloud切换至MongoDB,重新部署即可。下面我们就重点来聊聊遇到的坑。

导出数据错误: Waline版本不匹配

导出数据可以通过评论的后端完成: https://xxx.vercel.app/ui

Waline Migration UI

导出评论时出现如下错误:

Failed to load resource: the server responded with a status of 500 () https://xxx.vercel.app/comment?type=count&url=%2Fsample%2F

Waline Version Mismatch

Debug好久才发现,服务端(v2.6.2)与客户端(v1.6.0)版本不匹配所致,先得升级OldApp到v2.6.2,重新部署一次OldApp即可。

导入数据504错误

好容易导出了json数据,结果在导入数据时又出现了问题。

发现无论导多少次,只能一次导入约40条数据,就出现"504"错误。看vercel.app的后台日志发现,POST请求超时了,# Hobby版Serverless Function的执行时间最多只有10秒:

Serverless Function Execution Timeout (Seconds) 10

没有读导入的源码,看起来是导入数据行数过多,10秒插入不完导致API超时。应该是Waline导入数据的实现比较简单所致,没有使用块插入优化和异步导入机制。可以理解,导入导出对大部分用户来说并不是个常用的功能,做得简单些也无妨。

那么问题来了,如何将LeanCloud的数据导入MongoDB?有几种方案:

  • LeanCloud后台导出jsonl文件,写程序自行解析并插入MongoDB,看了一下数据格式,来回转换比较麻烦
  • 解析导出的waline.json文件,写程序插入MongoDB
  • 如果数据量不太大,可将数据分成如30行一个块,逐块手动导入MongoDB,由于每次导入会清除MongoDB表中内容,每次用MongoDB Compass的导出功能将此块内容导出,最后再将MongoDB Compass导出的json逐个导入进去

尝试写程序解析LeanCloud的数据格式,由于有日期和图片Base64编码的数据,解析和导入遇到了不少问题,最终采用第三种笨方法解决了问题。如果老数据量很大,还是得用前两种方案,其中第二种方案也未必奏效,利用Vercel导出大量数据一样会超时。

JWT Invalid Signature错误

导入数据后发现本地运行Hexo加载评论没问题,但部署后出现错误:

Waline.vue:262 Fetch comment list failed with 500: invalid signature

百思不得其解,查了下Vercel日志:

2022-07-31T04:14:27.552Z 314c32aa-1ca2-4cde-a720-a72d0be6a075 ERROR JsonWebTokenError: invalid signature at /var/task/node_modules/jsonwebtoken/verify.js:133:19 at getSecret (/var/task/node_modules/jsonwebtoken/verify.js:90:14) at Object.module.exports [as verify] (/var/task/node_modules/jsonwebtoken/verify.js:94:10) at module.exports.__before (/var/task/node_modules/@waline/vercel/src/logic/base.js:51:26) at module.exports.__before (/var/task/node_modules/@waline/vercel/src/logic/comment.js:5:17) at /var/task/node_modules/think-logic/index.js:33:42 at dispatch (/var/task/node_modules/koa-compose/index.js:42:32) at /var/task/node_modules/think-router-rest/index.js:31:12 at dispatch (/var/task/node_modules/koa-compose/index.js:42:32) at Router.parseRule (/var/task/node_modules/think-router/router.js:266:17)

JWT token错误,在网页端退出再重新登录即可解决问题,真是一波三折。

切换文章阅读量至Waline

参考 # Waline浏览量统计 文档。

如果使用@waline/hexo-next插件(这里是v3.0.1),仅需修改Hexo根目录下的_config.yml中的waline段:

waline:
  ...
  pageview: true

同时,一定要将NexT主题中的leancloud_visitors disable:

leancloud_visitors:
  enable: false

此时,网站中的所有文章访问量统计都已切换为Waline浏览量统计。另一个问题来了,也需要数据迁移,不过这个操作简单许多,一般来说文章量都不太大,直接从LeanCloud导出文件,用Excel处理下,再导入MongoDB即可,访问量文档格式很简单,waline.Counter Collection示例文档:

{
  "_id": {
    "$oid": "62e6696e8f46698ea8a8f475"
  },
  "url": "/example/",
  "time": 86
}

BTW,前些天自行开发了个网站访问量统计工具,现在看来,全站访问量也可通过Waline浏览量统计实现,改下前端参数serverURLpath,再在每个页面都加上这段额外的js即可。

其他优化

MongoDB加索引

随着数据量增多,为提升访问效率,MongoDB的Collection需要加些索引,Waline本身没有做这部分的优化。

  • waline.Counter Collection: url和time两列需要加索引。
  • waline.Comment Collection: 加联合索引 <url, status, insertedAt>,可提升每篇文章评论的读取速度。

改变评论显示文字

利用 Hexo数据文件NexT多语言支持,在Hexo目录下(而非NexT的目录)source/_data/languages.yml (如无则创建):

en:
  post:
    comments:
      waline: Comments
zh-CN:
  post:
    comments:
      waline: 评论

至此,已彻底去除LeanCloud依赖。全站使用的服务:GitHub Pages + Vercel App + MongoDB。