用 Cloudflare Worker 给 Hexo 博客加上真实的访问统计(零本地依赖)
想给博客的 about 页加一个「今日访问 / 本月访问」之类的统计区块,又不想塞一堆第三方 JS(busuanzi、51la 那种会拖慢页面、还有隐私顾虑)?如果你的博客已经托管在 Cloudflare,其实有一套最干净的做法——直接读 Cloudflare 自己的 Analytics 数据。
本文记录我是怎么用 Cloudflare Worker + KV + Cron Trigger,把真实的 zone 级 PV/UV 自动喂给 Hexo 博客的 about 页的。整套方案跑在 Cloudflare 上,零本地依赖,关了电脑数字也会每天自动刷新。
快速结论
- 博客在 Cloudflare + 绑了自定义域名 → 用本文方案,同源、国内快、无 CORS,最稳。
- 不想碰 Worker → 写个本地脚本定时拉 GraphQL 改 about 数据再部署,也能用,但机器得一直开着。
- Cloudflare 没有公开的前端 API → 必须有一个服务端(Worker / 本地脚本 / Actions)拿 Token 去调 GraphQL。
为什么不用第三方统计
常见的不蒜花、51la 都是往页面里塞一段 JS 做计数或埋点。问题有两个:
- 侵入性强:多一个外部请求、多一段脚本,对”白嫖”静态博客来说是额外负担。
- 数据是「自己数自己」:不蒜花是客户端计数,刷一下就 +1,跟 Cloudflare 后台看到的真实流量对不上。
而 Cloudflare 已经在边缘节点帮你统计了所有请求,GraphQL Analytics API 能拿到真实的 PV、UV、请求数、地理分布。直接复用这份数据最准,也最省事。
三种方案对比
| 方案 | 跑在哪 | 优点 | 缺点 |
|---|---|---|---|
| A. 本地脚本 + 定时 | 你自己机器 | 复用现有构建管线,Token 不出本机 | 机器/服务得一直开着 |
| B. GitHub Actions | GitHub 云端 | 免费、定时稳,Token 存 Secrets | 博客源码得推到 GitHub |
| C. Worker + KV(本文) | Cloudflare 云端 | 同平台、同源无 CORS、关电脑也自动跑 | 要写一点 Worker 代码 |
博客本身就在 Cloudflare Pages 上,方案 C 几乎是天作之合:Worker 和博客同域,前端 fetch 自己的接口没有跨域问题,Token 只存在 Worker Secret 里,绝不落到前端。
架构
1 | 每天 UTC 00:30 Cron Trigger |
- Worker:负责定时拉数、写 KV、响应前端读请求
- KV:缓存聚合后的 JSON,避免每次访问都打 GraphQL
- Cron:每天自动刷新,KV 空时首次访问还会冷启动自动拉一次
准备工作
去 Cloudflare 后台拿两样东西:
- Zone ID:点进你绑定的自定义域名 → Overview 页面右下角 → 一串 32 位十六进制。
- 只读 API Token:右上角头像 → My Profile → API Tokens → Create Token → 选预设模板 **”Read analytics and logs”**(只有读权限,改不了任何东西)→ 复制 Token。
注意:博客必须绑了自定义域名,且域名 DNS 托管在 Cloudflare。因为 GraphQL 的
httpRequests1dGroups是按 zone 查的,*.pages.dev公共子域不在你自己的 zone 里,取不到数据。
步骤一:写 Worker
核心逻辑就三块:拉 GraphQL、聚合、读写 KV。完整代码如下:
1 | /** |
步骤二:wrangler.toml
1 | name = "blog-analytics" |
步骤三:部署 Worker
1 | # 1. 建 KV namespace,记下返回的 id 填回 wrangler.toml |
部署完成后,访问 https://your-domain.example.com/api/stats/ 应该返回类似:
1 | { |
步骤四:前端 about 页
我用的是 Solitude 主题,它的 about 页模板支持一个 tj 字段渲染访问统计区块,内置 custom 模式:指定一个返回上面 JSON 的接口地址,模板就会 fetch 它并填进 #statistic。在 source/_data/about.yml 里这样配:
1 | tj: |
只要 tj 下没有 static 字段,构建时的静态注入逻辑会自动跳过,完全交给前端运行时 fetch。如果是其他主题,思路一样:在 about 页模板里加一段 fetch('/api/stats/').then(r=>r.json()).then(填充 DOM) 即可。
踩坑记录
折腾过程中几个坑,提前说能省不少时间:
- GraphQL 查询跨度上限是 52 周 1 天。一开始写
now - 365天会越界报错,改成now - 364天(即Date.now() - 364*864e5)才正常。 wrangler kv key put默认写本地 KV,边缘节点读不到。手动写数据必须加--remote:wrangler kv key put stats --path=stats.json --binding=STATS --remote。- Token 绝不能放前端。Worker 的
fetch在同域下不需要 Authorization 头,Token 只在 Worker 服务端用,存到wrangler secret put CF_API_TOKEN即可,源码和前端都看不到。 - 路由挂自定义域名比 workers.dev 稳。国内访问 workers.dev 域名可能被墙,挂在博客自己的域名下(
your-domain/api/stats*)同源又快。
日常维护
- 数字每天 UTC 00:30 自动刷新,不用管。
- 想手动强刷:
https://your-domain.example.com/api/stats/?refresh=1&key=。 - KV 意外为空时,Worker 被首次访问会冷启动自动拉一次,不会空白。
结语
这套方案把”显示真实访问量”这件小事,收敛成了 Cloudflare 平台内的一个闭环:Worker 负责取数、KV 负责缓存、Cron 负责定时,前端只管读。没有第三方脚本、没有隐私顾虑、也没有本地服务要维护。博客在 Cloudflare 的朋友,强烈建议直接复用这套思路。





