前言 目前我使用的评论是 Waline,总体来说 体验还算可以。但是在使用过程中也遇到过一些问题,比如加上邮件推送后, 评论的速度会变的很慢。
研究过后发现 Waline 貌似是在评论时 直接进行发送邮件的,同步进行发信便会导致评论耗时较长,很影响用户体验,有时评论需要耗时几秒甚至超时。
Waline 应该是使用的 ThinkJs,理论上可以通过异步函数来进行异步发信,不清楚为什么要同步发信。由于我对于 ThinkJs 并没有太深入了解,直接修改源码也可能造成部署麻烦,于是我尝试寻找另外的方式来实现异步发信,在研究过后, 发现 Waline 可以设置一个 Webhook 地址,在评论时会自动向该地址发送一个 POST 请求。
其 POST 内容大致为:
评论文章时:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 { "type" : "new_comment" , "data" : { "comment" : { "link" : "https://blog.example.com" , "mail" : "email@example.com" , "nick" : "xcsoft" , "ua" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.115 Safari/537.36" , "url" : "/" , "comment" : "test" , "ip" : "127.0.0.1" , "insertedAt" : "2022-07-09T13:46:52.085Z" , "status" : "approved" , "objectId" : 1 , "rawComment" : "test" } } }
回复别人评论时:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 { "type" : "new_comment" , "data" : { "comment" : { "link" : "https://blog.example.com" , "mail" : "email@example.com" , "nick" : "xcsoft" , "pid" : 1 , "rid" : 1 , "ua" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.115 Safari/537.36" , "url" : "/" , "comment" : "[@xcsoft](#1): reply" , "ip" : "127.0.0.1" , "insertedAt" : "2022-07-09T13:47:53.526Z" , "user_id" : 1 , "status" : "approved" , "objectId" : 2 , "rawComment" : "reply" } , "reply" : { "user_id" : null , "comment" : "test" , "insertedAt" : "2022-07-09 21:46:52" , "ip" : "127.0.0.1" , "link" : "https://blog.example.com" , "mail" : "email@example.com" , "nick" : "xcsoft" , "rid" : null , "pid" : null , "sticky" : null , "status" : "approved" , "like" : null , "ua" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.115 Safari/537.36" , "url" : "/" , "createdAt" : "datetime('now', 'localtime')" , "updatedAt" : "datetime('now', 'localtime')" , "objectId" : 1 } } }
实现 了解了 Webhook 内容后, 便打算使用 golang-gin 开发服务端, 得益于 Golang 的协程 异步发信还是很方便的。
我这里直接通过 gin 提供的 ShouldBindJSON
来解析 Waline 发送的 json, 其结构体类似
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 type CommentStruct struct { Type string `json:"type"` Data struct { Comment struct { Nick string `json:"nick"` Mail string `json:"mail"` Url string `json:"url"` Comment string `json:"comment"` RawComment string `json:"rawComment"` Ip string `json:"ip"` InsertedAt string `json:"insertedAt"` Status string `json:"status"` } `json:"comment"` Reply struct { Nick string `json:"nick"` Mail string `json:"mail"` Comment string `json:"comment"` InsertedAt string `json:"insertedAt"` Status string `json:"status"` } `json:"reply"` } `json:"data"` }
其中 Type
始终为 new_comment
, Data.Comment
为评论信息, Data.Reply
为被回复信息(可能为空)
邮件采用的是 gomail 库, 由于大多数服务商默认是有发送频率限制的, 于是我通过 Redis 实现了一个消息队列, 用来控制发信频率。
发信效果
模版及图片 来源于网络
开源 源码以 Apache 2.0 协议开源于 soxft/waline-async-mail
基本部署方式可以在 wiki 找到