Hexo去LeanCloud依赖
7.19日,收到了LeanCloud的邮件,大意如下:
8 月 1 日起,LeanCloud 国际版共享域名不再向中国大陆提供服务
为履行合规责任,降低平台风险,LeanCloud 国际版共享域名将于 2022 年 8 月 1 日起不再向中国大陆的最终用户提供服务,国际版共享域名仅服务于海外用户。
静态网站的状态存取是个痛点。好消息是本站使用Hexo
NexT主题,天然集成了文章阅读量的功能,后端存储是LeanCloud,仅需配置app_id
与app_key
。而评论系统是另一个坑,一年前
切换到了Waline,一举攻克了这个难题,但当时Waline也依赖于LeanCloud。
这次LeanCloud国际版共享域名不向中国大陆提供服务改动,对Waline无影响,因为Waline的前端部署在Vercel海外节点。但如果网站面向大陆用户,文章阅读量统计会受影响。
因此,考虑将本站去LeanCloud依赖。方法很简单,将文章阅读量切换至Waline,同时Waline的后端存储改用MongoDB。去依赖需要你有一台服务器,自建MongoDB,或者直接使用 MongoDB Atlas的免费版 。
使用MongoDB存储数据的好处:
- 速度更快,LeanCloud访问速度一言难尽
- 数据自己存储,非常灵活,方便导入导出
- 去除LeanCloud API存储依赖(引入MongoDB依赖 :-) )
切换Waline后端存储
看起来很简单,参考 # 多数据库服务支持 。实际操作还是踩了不少坑,主要痛点是已有数据的导出和导入。
切换存储很简单,仅需改变下Vercel前端的环境变量,并重新部署令其生效。保险起见,强烈建议新建项目,方便导出导入数据。方便描述,两个Vercel
app用OldApp
和NewApp
进行指代。
先在NewApp
配置如下MongoDB的相关环境变量:
值得一提的是MONGO_HOST
与MONGO_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
导出评论时出现如下错误:
Failed to load resource: the server responded with a status of 500 () https://xxx.vercel.app/comment?type=count&url=%2Fsample%2F
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浏览量统计实现,改下前端参数serverURL
和path
,再在每个页面都加上这段额外的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。