我给博客加了评论:让静态站重新长出一点现场感
这两天给博客补上了评论功能。它不是一个很大的功能,但对这个站点很重要:博客终于不再只是我单向往外写东西,而是可以开始接住读者的反馈、补充、质疑和建议了。
以前这个站更像一个安静的记录本。文章发出去之后,读者如果有想法,最多只能在其他地方找我,或者干脆就算了。对一个记录 AI、产品、自动化和独立开发过程的博客来说,这其实有点可惜。
因为很多文章不是“教程发布完就结束”,而是在记录真实过程:哪里踩坑了、哪一步判断错了、哪个方案后来证明不行、读者有没有遇到类似情况。这类内容特别需要现场反馈。
所以我给 nmdft.cn 加了一个自建评论系统。
为什么要给博客加评论
评论看起来是博客的标配,但在静态站里,它其实不是默认能力。
静态博客的好处很明显:
- 访问快;
- 成本低;
- 页面稳定;
- 维护简单;
- 内容都在仓库里,比较可控。
但它也有一个天然问题:页面本身没有后端。文章可以生成成 HTML,但用户提交评论这件事,需要有地方接收、保存、再展示出来。
过去很多静态博客会接第三方评论系统,比如 Disqus、Gitalk、Giscus、Valine、Waline 等。它们各有优点,但我这次没有直接选现成服务,而是做了一个很小的自建版本。
原因也简单:这个博客现在不是一个纯展示站,而是我的长期工作台之一。我希望它的反馈数据、交互方式、后续扩展,都尽量掌握在自己手里。
这和我现在做产品的思路也一致:先做一个能跑通闭环的小能力,不一开始追求完整平台。
这次做出来了什么
现在文章页底部已经可以看到评论区。
当前功能很克制:
- 读者可以在文章页发表评论;
- 邮箱必填,但不会在前台公开显示;
- 用户名可填,不填会根据邮箱自动生成一个名字;
- 评论内容按纯文本展示,不支持 HTML;
- 前端会对内容做转义,避免把评论变成注入入口;
- 同邮箱或同 IP 短时间内不能频繁提交;
- 可以通过环境变量开启审核模式;
- 可以配置简单敏感词,命中后进入待审核;
- 评论按文章路径区分,不同文章互不混在一起。
也就是说,它不是一个“社交系统”,更不是一个论坛。它只是让每篇文章多一个真实反馈入口。
我现在更看重这件事:读者能不能顺手留下一句真实反馈。
功能越重,越容易把人挡在门外。一个博客评论系统,第一阶段没必要复杂到需要登录、绑定账号、做个人主页、做通知中心。先让评论这件事发生,后面再看真实需求。
技术方案:静态页面 + 云函数 + MySQL
这次的实现方式大概是这样:
1 | |
页面仍然是 Hexo 生成的静态页面,主题还是 Fluid。评论区通过一个自定义的 nmdft 评论组件挂到文章页底部。
前端脚本负责两件事:
- 打开文章时,根据当前文章路径请求评论列表;
- 用户提交评论时,把邮箱、用户名、内容和文章路径发到
/api/comments。
后端则放在 EdgeOne Pages 的 Cloud Functions 里,负责:
- 初始化评论表;
- 校验邮箱和内容长度;
- 规范化文章路径;
- 保存评论;
- 查询指定文章的已通过评论;
- 做基础限频;
- 根据配置决定评论是直接通过,还是进入待审核。
数据库用的是 MySQL 兼容方案。表结构也很简单,核心字段包括:文章路径、父评论 ID、作者名、邮箱、邮箱 hash、内容、状态、IP hash、User-Agent、创建时间和更新时间。
这里有一个小取舍:邮箱会保存到数据库里,因为后面可能用于识别评论者、限频、通知或管理;但前台不会公开显示邮箱,只显示用户名和一个由邮箱生成的公开 hash,用来稳定头像颜色。
为什么不一开始做得很复杂
评论系统很容易越做越大。
比如马上就可以想到这些需求:
- 管理员后台;
- 评论审核列表;
- 邮件通知;
- 回复功能;
- 删除和举报;
- 邮箱验证码;
- 反垃圾评论;
- 黑名单;
- OAuth 登录;
- Markdown 支持;
- 评论订阅。
这些都可以做,但如果第一阶段就全做,可能会变成另一个“大而未完”的项目。
所以这次的原则是:先把最短链路跑通。
最短链路只有四步:
- 文章页能显示评论区;
- 读者能提交评论;
- 评论能保存到数据库;
- 页面能重新加载并展示评论。
只要这四步稳定,评论系统就已经开始创造价值了。后面的审核、通知、反垃圾、回复,都可以在真实使用中逐步补。
这其实也是我最近越来越认可的一种开发方式:不要为了“看起来完整”而推迟上线。先让一个小闭环活起来,再根据真实反馈决定下一步。
中间踩到的几个小坑
这次功能不算复杂,但也不是一次写完就顺利。
中间主要修了几类问题。
第一类是数据库连接问题。云函数环境和传统长驻服务不一样,如果连接池设置得太随意,很容易造成连接压力。后来把连接池控制得更保守,避免为了一个轻量评论功能给数据库制造额外负担。
第二类是查询兼容问题。评论列表一开始用了预处理查询,在线上环境里表现不稳定,后来改成更稳的查询方式,同时对路径和 limit 做了控制,确保查询范围可控。
第三类是调试问题。线上函数出错时,如果只返回一句“加载失败”,定位会很难。所以临时加了 debug 模式,通过参数暴露构建标记和错误信息,方便确认到底跑的是不是最新版本、错在哪里。正常情况下,前台不会把内部错误细节暴露给读者。
第四类反而是样式问题。评论区加上之后,文章页整体高度、头图、移动端展示都要一起看,不然一个功能好了,页面观感又乱了。最后顺手把不同页面类型的 hero 高度也统一了一下。
这也是做自己站点时常见的情况:一个小功能,最后会牵出部署、样式、数据库、隐私和运维的连锁问题。
这件事对博客意味着什么
我不觉得评论区只是一个“互动组件”。对这个博客来说,它更像是一个小小的反馈基础设施。
以后很多文章都可以不只是发布结论,而是持续接住后续信息:
- 有人指出我的判断哪里不对;
- 有人补充一个更好的工具;
- 有人讲自己也踩过同样的坑;
- 有人提出一个可以继续做的小需求;
- 有人告诉我某篇文章里的方案已经过时了。
这些反馈如果只散在聊天里,很快就消失了。但如果它们留在文章下面,就会变成内容的一部分。
这和我做“痛点共创平台”的想法其实是同一条线:不要只记录单向表达,要把真实反馈接回来。很多有价值的产品线索、改进方向和判断修正,都是从一句具体评论开始的。
后面还会继续补什么
评论系统现在只是第一版。后面我大概率会按真实使用情况补这些能力:
- 审核后台:不用直接改数据库,也能处理 pending、spam、deleted;
- 邮件通知:有新评论时提醒我,不然评论区容易变成无人看管的留言箱;
- 回复功能:现在表结构已经预留了
parent_id,后面可以支持楼中楼或简单回复; - 更强的反垃圾策略:如果垃圾评论变多,再接入更严格的检测;
- 评论管理脚本:先用轻量脚本解决管理问题,不急着做完整后台;
- 和文章运营联动:把高质量评论转化成文章更新、FAQ 或后续选题。
但这些都不是今天最重要的事。
今天最重要的是:评论这条链路已经通了。
小结
这次给博客加评论,表面上是一个小功能,实际是在补一个长期写作站点很关键的能力:反馈入口。
我没有直接把它做成一个复杂系统,而是先用静态博客、云函数和 MySQL 跑通最小闭环。它现在还很朴素,但已经足够让读者在文章下面留下真实想法。
对我来说,这就够了。
一个长期博客不应该只是不断往外发文章。它也应该慢慢长出耳朵,听见读者在说什么。