作者给自己的 Cloudflare Pages 博客加了一套站内访问量统计:访客能直接在文章页看到阅读量、在页脚看到全站访问量,数据全部存在自己的 KV 里,并顺手把积压的依赖漏洞从 168 个压到 17 个。
🤔 为什么不用现成统计
Google Analytics 或作者此前用的 HanAnalytics 都能统计,但访客在页面上什么都看不到,且要么把数据喂给巨头、要么再起一个服务,违背了他「能不花钱、能不麻烦就不麻烦」的原则。而 Pages 自带的 Pages Functions 与 KV 全在免费额度内,正合适。
🧱 方案与防重复计数
在 functions/api/views.ts 里写一个接口,用 KV 命名空间当计数器:POST 自增、GET 读取;全站访问量存在固定 key,每篇文章按 location.pathname 单独计数。前端用 ViewCounter 组件首次加载拉一次数据,并监听 Swup 的 page:view 事件,无刷新切换页面后再次更新。作者明确说明自己按每次加载都 +1 统计,刷新会略虚高。
⚠️ 部署必做动作
代码推上 GitHub 后 Pages 会自动构建,但还要在「设置 → Functions → KV namespace bindings」里把命名空间绑定上去,变量名必须叫 VIEWS(对应代码里的 env.VIEWS),然后重新部署;否则 /api/views 会报错、计数器一直停在 —。剩余的 17 个漏洞全部来自 astro 自身,需大版本升级才能清零,作者选择先跟随上游节奏。
前言
我的博客一直托管在 Cloudflare Pages 上,借着 “赛博菩萨” 的免费额度,过得还算滋润。之前写过一篇用 HanAnalytics 做网站统计的文章(那篇在这儿),那个方案说白了是给我自己看的——想看数据还得登录后台一层层点开,访客是无感的。
但作为一个有点强迫症的站长,我总觉得少了点东西:来访的你,能不能在页面上直接看到这篇文章被读过多少次?全站又一共被访问了多少次?这种 “热腾腾” 的访问量数字,才是博客的烟火气嘛。
于是趁着周末有空,我给小站接上了一套站内访问量统计,顺手还把积压已久的依赖漏洞修了一波。下面聊聊思路和踩坑。
一、为什么不直接用现成统计
你可能会说:装个 Google Analytics、或者我之前用的 HanAnalytics 不就行了?
确实能统计,但它们有两个让我不太舒服的点:
- 访客看不到:数据是站长的私产,访客在页面上什么都看不到,少了点互动感;
- 依赖第三方:要么喂巨头数据,要么再起一个服务,违背了我 “能不花钱、能不麻烦就不麻烦” 的装机原则。
而我这博客本就跑在 Cloudflare Pages 上,它自带 Pages Functions(边缘无服务器函数)和 KV(键值存储),全都在免费额度内。把访问量存在自己的 KV 里、用 Pages Functions 做接口,数据完全自控、零额外服务——这不就是 “赛博菩萨” 的正确打开方式吗?
二、方案:Pages Functions + KV
思路很朴素:
- 在
functions/api/views.ts里写一个 Serverless 函数,接收路径参数; - 用 KV 命名空间当计数器,POST 就自增,GET 就读取;
- 前端每个页面加载时调一下接口,把数字渲染出来。
为了避免重复计数,我是这么设计的:
- 全站访问量:每次页面访问
+1,存到 KV 的固定 key(比如__site__); - 每篇文章访问量:文章页额外按当前路径
location.pathname自增一次,存成各自独立的 key。
这样一来,站点总数是所有页面的真实访问量,文章数各自独立,互不打架。
三、前端怎么接
本站用了 Swup 做无刷新页面切换,所以计数器不能只在首屏跑一次——切到另一篇文章时也得更新。我写了个小组件 ViewCounter:
- 初始加载时拉一次数据;
- 监听 Swup 的
page:view事件,页面切换后再拉一次。
于是文章页头部会显示 “阅读量 N”,页脚常驻 “全站访问量 N”。数字加载前先显示 —,拿到接口返回再填上,体验还算顺滑。
NOTE按我的习惯,这里统计的是 每次加载都
+1(包括刷新)。简单直观,虽然刷新会虚高一点点,但对一个个人博客来说无伤大雅。
四、顺手修了一波依赖漏洞
借着折腾的机会,我顺手做了一次依赖大保健。一跑 pnpm audit,好家伙——168 个漏洞,3 个 critical、79 个 high,吓得我手里的枸杞茶都洒了。
按 package.json 里的版本范围把直接依赖更新到最新兼容版,再用 pnpm.overrides 强制修掉几个麻烦的传递依赖:
serialize-javascript(构建链里的 RCE)brace-expansion(glob/minimatch 链的 DoS)sharp(libvips 相关)
一番操作下来,168 → 17。剩下的 17 个,全部来自 astro 自身——官方公告里写着修复版本是 astro >= 7.0.4,也就是说得做大版本破坏性升级才能清零。
我去翻了翻上游 saicaca/fuwari,发现官方主线也还停留在 astro 5.x,同样带着这 17 个漏洞;他们连 Dependabot 都设成了 “忽略所有大版本更新”,显然也是在等一个合适的时机再大改。既然上游都没急,我这小破站也就先停在这里,等哪天有空再跟着上游的 Tailwind v4 迁移一起把 astro 升上去。
五、部署注意点
代码推上 GitHub 后,Cloudflare Pages 会自动构建。但要让计数器真正跑起来,还有一个必做动作:
在 Pages 项目 设置 → Functions → KV namespace bindings 里,把新建的 KV 命名空间绑定上去,变量名必须叫 VIEWS(和代码里的 env.VIEWS 对应),然后重新部署一次。
没绑定的话,/api/views 会因为找不到 KV 而报错,计数器就会一直停在 —。
结语
一套站内访问量统计,加上一次依赖大保健,小站又健康了一点。现在你能在每篇文章底下看到它被读过多少次,也能在页脚看到全站的热度——如果你愿意,多点几下刷新,帮我把数字刷好看点(不是)。
下次再聊,可能是 astro 7 的迁移实录了。在那之前,欢迎常来逛逛,你的每一次访问,KV 都记着呢。