第七部分:浏览统计
本部分是「字数 / 阅读时间 / 浏览量」统计功能的完整教程,包括环境变量配置、Cloudflare Worker 部署与故障排查。
7.1 功能概览
| 展示位置 | 内容 | 数据来源 |
|---|---|---|
| 文章详情页 | 字数 / 阅读时间 / 浏览量 徽章行 | 构建期计算 + Umami |
| 页脚 | 全站总浏览量(与 Built at 同行) |
Umami 查询 |
- 字数与阅读时间:构建时由
lib/reading.ts计算,写进静态页面,不发请求。 - 浏览量:页面加载后由
lib/umami.ts运行时查询 Umami。
三个徽章只显示图标 + 数字,不显示文字标签,含义通过 title / aria-label 走 i18n(六种语言)。
7.2 环境变量
# Umami Website ID(必填,留空则统计功能整体禁用)
NEXT_PUBLIC_UMAMI_WEBSITE_ID=your-website-id
# Umami 分享链接 ID(Share 链接里的那段,推荐用它,只读)
NEXT_PUBLIC_UMAMI_SHARE_ID=your-share-id
# 可选:只读 API Key(优先于 Share ID)
NEXT_PUBLIC_UMAMI_API_KEY=
# 可选:Cloudflare Worker 地址(查询代理 + 上报转发)
NEXT_PUBLIC_UMAMI_PROXY_URL=https://your-worker.workers.dev
禁用方式:
NEXT_PUBLIC_UMAMI_WEBSITE_ID留空 → 不注入统计脚本,徽章与页脚总浏览量整体消失;WEBSITE_ID有值,但 Share ID / API Key / Worker 地址三者全空 → 同样禁用(没有可用的数据通道)。
注意:所有 NEXT_PUBLIC_ 前缀变量在构建时打进前端 bundle,请只放公开标识符,不要放高权限密钥。修改后需重启 dev server / 重新构建。
7.3 获取 Umami 凭据(免费版)
- 注册/登录 cloud.umami.is
- 新建 Website(Website URL 填你的站点域名)
- 在 Website 设置里复制 Website ID
- 创建 Share Link,从分享地址
https://cloud.umami.is/share/{SHARE_ID}中取出SHARE_ID - (可选)在设置里创建只读 API Key —— 注意它会明文进前端 bundle,只建议在分享链接不可用时使用
7.4 为什么要部署 Cloudflare Worker
浏览器可能拦截对 cloud.umami.is / gateway.umami.is 的请求(Firefox 增强型跟踪保护、广告拦截插件),导致:
- 数据上报失败 → 浏览量一直是 0
- 统计查询失败 → 徽章、页脚总量不显示
scripts/umami/worker.js 在你自己的域名下做两件事:
- 查询代理:
GET /?path=/posts/xxx/→ 转发到 Umami,返回{"views": 123}- 不带
path参数即返回全站总量(页脚用) - 结果缓存到 CF 边缘 180 秒,
Cache-Control: max-age=180
- 不带
- 上报转发:
POST /api/send→ 转发到官方 gateway,让浏览器只看到向你的 worker 域名发请求
7.5 部署 Worker
-
打开 Cloudflare Dashboard → Workers & Pages → Create → Create Worker
-
把
scripts/umami/worker.js全文粘贴进编辑器 → Deploy -
复制 Worker 地址(形如
https://xxx.workers.dev),填入NEXT_PUBLIC_UMAMI_PROXY_URL -
在 Worker 的 Settings → Variables 里填入必填配置(源码内没有任何真实 ID,缺任一项真实请求一律返回 503 并列出缺失项):
变量 说明 示例 WEBSITE_IDUmami Website ID your-website-idSHARE_IDUmami 分享链接 ID your-share-idALLOWED_ORIGINS允许跨域的站点来源,逗号分隔 https://your-domain.example -
重新构建并部署站点
本地开发不需要配置:Origin 为
localhost时 Worker 直接回示例数据(见下方"示例数据模式")。
安全加固(已内置)
- CORS 来源白名单:白名单来自
ALLOWED_ORIGINS环境变量(必填,源码不保存任何真实域名/ID),按请求 Origin 回显,名单外的来源拿不到Access-Control-Allow-Origin,浏览器会直接拦截;localhost/127.0.0.1内置放行(仅示例数据模式) - 上报 Origin 校验:带 Origin 且不在白名单 → 403;无 Origin(curl / 服务端脚本)放行,由
payload.website必须匹配本站兜底,防止 Worker 被当成公共中继给别人刷数据 - 扩展白名单:需要放行更多域名时,在 Worker 环境变量里加
ALLOWED_ORIGINS=https://a.com,https://b.com
本地开发:示例数据模式
Origin 为 localhost / 127.0.0.1 时,Worker 只回示例、不做真实操作:
| 请求 | 返回 | 行为 |
|---|---|---|
| 查询 | {"views":128,"demo":true} |
不查 Umami、不进缓存 |
| 上报 | {"demo":true} |
应答后丢弃,不入库 |
本地开发因此不会污染真实统计,也不消耗 Worker 配额。看到徽章显示 128 是正常现象,部署到线上(正式域名)即为真实数据。
7.6 验证是否生效
- 打开你的博客,F12 → Network 过滤
send:应指向https://xxx.workers.dev/api/send且状态 200(没有"拦截中") - 浏览几页后,访问 Worker 地址
https://xxx.workers.dev/?path=/,应返回{"views": n} - 刷新文章页,徽章应显示浏览量 —— 结果有 3 分钟边缘缓存,稍等或强刷即可
- 打开 Worker 地址时带上任意 Origin(浏览器访问你的站点即自动带),确认返回的
Access-Control-Allow-Origin是你的域名
7.7 常见问题
Q: 徽章不显示 / 一直为 0?
A: 按顺序排查:
NEXT_PUBLIC_UMAMI_WEBSITE_ID和NEXT_PUBLIC_UMAMI_SHARE_ID是否已配置(改完要重启 dev server / 重新构建)- 控制台是否有
cloud.umami.is或gateway.umami.is被拦截 —— 被拦就部署 Worker 并配置NEXT_PUBLIC_UMAMI_PROXY_URL - Umami 后台 Realtime 是否有访客(没有 = 上报被拦,同样走 Worker)
- 本地 dev 显示 128 = 示例数据模式,属正常;线上为 0 才是异常
- 线上部署后记得在 Cloudflare Pages 环境变量里也配上
NEXT_PUBLIC_UMAMI_PROXY_URL并重新构建
Q: 浏览量数字有延迟?
A: Worker 结果带 max-age=180 边缘缓存,新浏览量最多滞后 3 分钟。想立即刷新,访问 https://xxx.workers.dev/?path=/posts/xxx/&t=任意随机值(加任意参数换缓存 key,等于强制回源)。
Q: 想关掉浏览统计?
A: 把 NEXT_PUBLIC_UMAMI_WEBSITE_ID 留空即可,统计脚本、徽章、页脚总量会整体消失,字数与阅读时间不受影响。
7.8 总结
| 步骤 | 要点 |
|---|---|
| 1. 获取 Umami 凭据 | Website ID + Share ID |
| 2. 配置环境变量 | .env / Cloudflare Pages 两处都要配 |
| 3. 部署 Worker(推荐) | 粘贴 scripts/umami/worker.js → Deploy |
| 4. 验证 | Network 的 send 请求 200 + 后台有访客 |
完成后,文章页会有「字数 · 阅读时间 · 浏览量」徽章,页脚会显示全站总浏览量。