解决不蒜子文章阅读计数错误的问题
本博客应用Hexo框架和NexT主题构建,并一直使用不蒜子 (busuanzi)提供的访客和阅读次数统计功能。但是,最近几个月发现统计数据没有实时更新,而且不同浏览器显示的计数也不一样。经过一番查询和调研,终于找到解决办法。
问题描述
NexT主题已集成了不蒜子的访客人数和文章阅读统计功能,下面是本博的主题配置文件中的相关部分
1 | busuanzi_count: |
这些设置分别对应:
- 首页底部显示的总访客人数和总阅读次数
- 点击“阅读全文”时显示的当前文章阅读次数
然而,从一开始我就发现单个文章的阅读计数在 macOS 的 Safari 浏览器中显示异常 —— 刚发的文章的阅读量就是一个很大的数字。在谷歌的 Chrome 和火狐浏览器中则显示正常阅读统计数值。因为太忙,而且只有 Safari 存在问题,就没有去花时间深究。
可是,在过去的几个月里,发现所有的浏览器都无法显示文章阅读计数值。打开文章后,在标题下面根本就没有“阅读次数”这一数据项。所以,现在不得不着手解决这一问题。
原因分析
网络搜索后发现原来 Safari 浏览器的阅读量显示错误是许多人都遇到的问题。Safari 浏览器默认都是阻止跨站点跟踪(cross-site tracking)的。要修复,只要在 Safari 设置的 “PRIVACY & SECURITY” 部分,关掉 “Prevent Cross-Site Tracking” 选项即可。
但是,还有一个更大的问题。不蒜子计数器的工作原理是在引入的 JavaScript 脚本中,把当前页面 URL 注册到其第三方服务器,服务器上保存对应的计数值,点击页面后通过更新服务器上的计数值,并在页面初始化时在本地标签加载、显示计数值。不蒜子统计博客文章访问量是通过 Referrer 来计算的。
什么是 Referrer?
简单理解,就是请求 Web 服务器时,可以在 HTTP Request 的请求头 (header) 中加上当前页面的 URL,例如我们在浏览某个博客页面,需要加载一些图片,从服务器请求这些图片时,Referrer 就是当前的博客页面 URL。从这里也可以看出,Referrer 可能会暴露请求来源的某些信息或者隐私,有一定的隐私或安全风险。
如果 Referrer Policy 是 strict-origin-when-cross-origin,不蒜子接收到的只有博客的域名,没有文章的具体路径,所以具体某个文章的 PV 统计会出现错误。所以,要想正确统计博客每篇文章的 PV,可以用 meta tag 把 Referrer Policy 设置为 no-referrer-when-downgrade。
即便如此,如果浏览器不尊重 meta tag,如上面提到的 Safari 默认阻止跨站点跟踪,就没法实现正确计数。基于 Referrer 的计数方法有太多限制,既不安全也不可靠,现在已经被认定为过时了。博客网站需要更有效的计数方案。
解决方案
参考一些讨论资料和其他博客的介绍,最后决定采用 Vercount 网站计数工具。Vercount 是一个基于 NextJS 和 Redis 的高效网站计数器,是一个不蒜子计数完美替代方案。它具有以下特点:
- 极速响应:服务器响应时间在 10ms 以内。
- 高可用性:支持中国加速版本或 Vercel 全球 CDN,确保 99.99% 的可用性。
- 精准统计:使用 POST 请求,克服传统 Referrer 方法在移动端和某些浏览器上的不足。
- 安全防护:采用 JSON 回调方式,杜绝 CSRF 攻击风险,了解更多请查看:JSONP。
- 自动数据同步:无需手动操作,
site_pv
、site_uv
和page_pv
数据会自动同步。 - 无缝兼容:支持不蒜子的
span
标签,轻松切换。 - 持久数据存储:使用 Redis 定期备份,确保数据不丢失。
- Serverless 架构:通过 Vercel Serverless Functions 提供后端支持,保证 99.99% 的可用性。
- 自托管:支持自托管,可以部署到任何支持 NextJS 的平台。
由于 Vercount 还没有集成到 Next 主题中,要在 Hexo 中实现和不蒜子一样的效果,得动手改些代码。修改分三步:
编辑不蒜子计数器的 njk(Nunjucks, 一个基于 JavaScript 的模版编辑语言)文件,用Vercount URL 替换不蒜子的 URL :
themes/next/layout/_third-party/statistics/busuanzi-counter.njk 1
2
3
4
5
6
{%- if theme.busuanzi_count.enable %}
- <script{{ pjax }} async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
+ <script defer src="https://vercount.one/js"></script>
+ {#<script{{ pjax }} async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>#}
{%- endif %}启用 NexT 配置中的 style: source/_data/styles.styl
themes/next/_config.yml 1
2
3
4
5
6custom_file_path:
#bodyEnd: source/_data/body-end.njk
variable: source/_data/variables.styl
#mixin: source/_data/mixins.styl
- #style: source/_data/styles.styl
+ style: source/_data/styles.styl在新的文件 styles.styl 文件中添加如下内容来覆盖默认行为:
source/_data/styles.styl 1
2
3
4
5
6
7
8
9
10
+#busuanzi_container_page_pv {
+ display: inline;
+}
+.busuanzi-count #busuanzi_container_site_uv {
+ display: inline;
+}
+.busuanzi-count #busuanzi_container_site_pv {
+ display: inline;
+}
修改完成后,重新生成博客即可。结果如下
可以看到,统计数据都恢复正常了。三种浏览器 Safari、Chrome 和火狐的显示结果也完全一致。Vercount 的替代方案工作得很好! 当然,缺憾是每次使用 npm 重新安装或升级后需要手动修改上面的相关源码。希望未来 Vercount 能直接集成到 Next 主题中,就可以省却这一麻烦了。