跳至正文

给博客加了3个新功能,踩了11个坑才跑通,差点把数据库干废了

上周闲着没事,翻了翻博客后台的访问统计,发现评论区的互动率掉了快一半。以前每篇文章底下还能吵个十几楼,现在连个“顶”都少见。琢磨了两天,觉得问题出在功能太寒酸——没有点赞、没有阅读进度条、文章分享到微信朋友圈还显示个光秃秃的链接。就这几样东西,拖了大半个月,周末终于全怼上去了。过程比我想的坑多,记录下。

先说点赞功能。这玩意看着简单,不就是加个心形图标点一下嘛,结果我栽在“重复点赞”和“取消点赞”的逻辑上。用的是Laravel 9,数据库里新建一张likes表,字段就四个:id、user_id、post_id、created_at。用户没登录的时候,点赞得用session_id代替user_id。第一版写完,测试发现连续点两下,数据库里插了两条记录。后来加了个唯一索引,UNIQUE KEY `unique_like` (`user_id`, `post_id`),再配合MySQL的INSERT … ON DUPLICATE KEY UPDATE,如果存在记录就软删除status字段改成0,不存在就插入。但问题来了,软删除之后重新点赞,得把status改回1,前端切换图标还得查当前状态。我直接换方案:每次点赞先查记录,有且status=1就走删除,有且status=0就走恢复,没有就走插入。逻辑是通了,但多了一次查询。后来改成用Redis缓存用户对某篇文章的点赞状态,key设计成`like:{user_id}:{post_id}`,过期时间设24小时。代码大概长这样:

“`
$key = “like:{$userId}:{$postId}”;
$cached = Redis::get($key);
if ($cached === null) {
$like = Like::where(‘user_id’, $userId)->where(‘post_id’, $postId)->first();
if ($like) {
$like->status = $like->status ? 0 : 1;
$like->save();
Redis::set($key, $like->status, ‘EX’, 86400);
} else {
Like::create([‘user_id’ => $userId, ‘post_id’ => $postId, ‘status’ => 1]);
Redis::set($key, 1, ‘EX’, 86400);
}
}
“`

不过Redis缓存跟数据库一致性问题没深究,反正点赞量不差那几百毫秒。

第二个功能是阅读进度条。就是文章顶部那根细线,滑到哪亮到哪。纯前端活,但坑在“文章内容动态加载”的情况。我博客文章用了Markdown解析,代码块里还有图片懒加载,页面高度不是一开始就确定的。直接监听scroll事件算`scrollTop / (documentHeight – viewportHeight)`,结果进度条卡在80%就不动了,因为图片加载完撑高了文档高度。解决方案是监听图片的onload事件,每次都重新计算高度。写了个debounce函数,300毫秒内只重算一次,不然图片一多性能崩了。核心代码:

“`
function updateProgress() {
const scrollTop = window.scrollY;
const docHeight = document.documentElement.scrollHeight;
const winHeight = window.innerHeight;
const progress = Math.min((scrollTop / (docHeight – winHeight)) * 100, 100);
document.getElementById(‘progress-bar’).style.width = progress + ‘%’;
}

window.addEventListener(‘scroll’, debounce(updateProgress, 300));
“`

但有个细节:如果文章特别短,不需要滚动,进度条应该直接100%还是隐藏?我选了隐藏,因为短文章用户一眼看完,进度条多余。判断条件就是`docHeight <= winHeight`时,直接display:none。

第三个功能最折腾——微信分享卡片。博客的域名是个人备案的,微信开放平台申请JS-SDK需要认证过的服务号,我没有。所以只能用最原始的meta标签方式。在文章页header里加了og:title、og:description、og:image。图片路径一开始写的是相对路径`/uploads/cover.jpg`,结果微信分享出去,图片裂了。因为微信抓取的时候,域名解析到的是`https://example.com`,但og:image没带域名,变成`https://example.com/uploads/cover.jpg`,按理说应该正常,但微信的爬虫有时候不走标准HTTP,会重定向到别的地方。后来全改成绝对路径,并且图片必须是正方形,最小尺寸300×300,否则微信不展示。还踩了个坑:og:description如果太长,微信会截断,只显示前80个字符。所以description我手动截取文章前120个字符,去掉Markdown符号,再trim一下。

这三个功能上线后,评论区活跃度还没恢复,但点赞量上来了,第一篇测试文章就收到了7个赞。不过代价是数据库里多了三张表,Redis内存多了几百KB,以及周末两天没出门。

总结几个血泪教训:第一,别信“简单功能一小时搞定”这种鬼话,光点赞的重复请求处理就花了半天。第二,前端进度条一定要考虑动态内容加载,懒加载图片、代码块折叠、广告位插入都会撑高页面。第三,微信分享的meta标签调试起来特别恶心,微信官方有个“微信公众平台接口调试工具”,但只能测access_token,测不了og标签。我用的笨办法:把文章链接发到文件传输助手,然后长按“收藏”,在收藏里看预览效果。更稳的是用微信的“爬虫模拟”工具,但得申请,我没搞。

最后,记得给点赞按钮加个防抖,不然手快的用户一秒点十下,Redis和MySQL都扛不住。


📎 延伸阅读

看完这篇,如果你想:

  • 直接拿工具 → 回复”13“,我把跨境获客工具包发给你
  • 系统学习 → 点击菜单”AI训练营”,从0开始跑通AI变现

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注