·更新于 2026年10月25日· 1 次浏览 Nuxt 3Vue 3Node.jsRedisMongoDB工程实践SEO流量统计
Nuxt 3 阅读量被刷新刷高:我用 Redis HyperLogLog、有效停留和来源过滤做真实统计
一次后台阅读量异常暴涨,让我意识到简单 +1 统计会被刷新、爬虫和广告参数污染。于是把阅读链路改成可去重、可过滤、可回查的方案。

作者
ZHOUYI
晚上看后台,一篇文章阅读量突然多出几千次。刚开始以为是推荐流量,点开日志发现大量同 IP 高频访问,还有自己反复预览、广告参数落地、爬虫抓取。原来的逻辑是详情页请求成功就 +1,刷新一次涨一次,数字好看但完全不能代表真实阅读。
先把“打开页面”改成“有效停留”
我没有在 Nuxt 3 页面初始化时直接上报,而是记录进入时间,等用户离开或页面隐藏时再判断。一般要求停留超过一个阈值,并且没有刚进来就切走。前端只负责采集,是否计数放到服务端判断,避免浏览器端被随意绕过。
用 Redis HyperLogLog 做低成本去重
HyperLogLog 的好处是省内存,适合这种允许少量误差的计数场景。我把指纹做成短期哈希,结合文章 ID 和日期,避免把普通访客当成同一人长期追踪。阅读量不是计费,不需要绝对精确,但要能挡住明显重复。
js
const key = `read:hll:${articleId}:${day}`;
const added = await redis.pfadd(key, fingerprint);
if (!added) return { counted: false };
const stayedMs = Date.now() - Number(enterAt || 0);
if (stayedMs < 8000 || hiddenTooSoon) return { counted: false };
await redis.incr(`read:valid:${articleId}:${day}`);
await ReadEvent.create({ articleId, fingerprint, stayedMs, ua, referrer });
return { counted: true };来源指纹和规则过滤
- 同一文章当天同指纹只算一次,HyperLogLog 判断新增。
- 停留过短、无可见性变化、频繁刷新的请求不计入。
- 广告参数、异常 UA、高频 IP 先进入灰名单,只记录不计数。
- 正文页参与统计,参数聚合页和预览页不参与,避免 SEO 参数稀释。
计数通过后,Redis 先做原子自增,保证实时数字稳定;MongoDB 再异步写入阅读事件,方便后续回查和修正。发现误判时,我不会直接改总数,而是重跑当天聚合,让数字有来源、有证据。
“阅读量不是虚荣指标。与其追求数字上涨,不如早点把无效流量挡在外面。简单 +1 很容易,但能解释每一次增长,才算真正做完。”