2026.06.09 (二)

✨ GPT-5.5 的摘要  

追查异常跳高的访问计数,阻止本地工作被计入访问量,并用 Cloudflare Worker 和 D1 添加公开聚合型 analytics 页面的记录。

访问计数器看起来不对。

一天的访问数突然超过了 80。

一开始也可以当作搜索流量处理。但感觉不对。最近几天我一直在修改博客,AI 工作过程中也多次打开本地服务器和公开 URL。

所以我开始怀疑。

这是真实访问吗?

还是我自己的工作也被计进去了?

计数器太诚实了

我先重新检查结构。

/zh-Hans/devlog/github-pages-blog/github-pages-blog-visitor-counter/ 中做的访问计数器使用 Cloudflare Worker 和 D1。

页面加载后,JavaScript 会向 Worker 发送 /track。Worker 再增加 D1 里的 counterspage_countersdedupe_views。Google Analytics 只作为 baseline,之后的增量保存在 D1。

问题是,这个结构太诚实了。

浏览器打开页面,就会计数。

本地开发服务器也指向 production Worker endpoint。Worker 的 CORS 允许 origin 里也有 localhost:4000127.0.0.1:4000

所以本地预览也可能增加真实的 production D1 计数。

dedupe 的基准也是 visitorId + path。同一个浏览器 10 分钟内重复打开同一页只算一次,但连续打开不同文章会全部计入 page view。

D1 里的值很明显。

day:2026-06-06 = 14
day:2026-06-07 = 38
day:2026-06-08 = 81
day:2026-06-09 = 5

2026-06-08 那天,旧 Daily Review 和 naver-* 文章被广泛地各打开了一次。比起真实读者,更像是工作过程中检查页面。

本地工作只显示,不计数

第一步修复很简单。

本地可以显示统计,但不能发送 /track

localhost
127.0.0.1
::1

这些环境下,客户端 JS 会跳过 tracking。

但只相信客户端还不够。如果 JS 出错,或者有人手动发请求,问题会回来。所以 Worker 也只允许 production origin 的 /track 真正计数。

TRACK_ALLOWED_ORIGIN=https://hyuk.blog

本地 origin 的请求现在会以 origin_not_tracked 被忽略。

我还加了 production QA 用的 opt-out。

?hyuk_no_track=1
?visitor_tracking=off
?visitor_tracking=on

这不是隐藏管理功能,而是我检查公开页面时避免污染计数器的开关。

统计不一定要隐藏

一开始我想做一个只有我能看的 analytics 页面。

后来发现没必要。

只要不保存原始 IP、原始 User-Agent、完整 referrer URL、单次事件日志就可以。只收集能公开的聚合值,统计页面本身也可以公开。

所以方向变了。

不是私有日志页,而是任何人都能看的公开博客统计页。

/analytics/

我把它加到顶部导航,也在侧边栏的小访问统计下面加了链接。

D1 只保存聚合

新表很简单。

analytics_daily_dimensions

date
dimension
value
count
updated_at

当一次 page view 真正被计数时,Worker 会分类公开维度,并按天累加。

维度包括:

page
content_group
locale
country
region
continent
colo
asn_org
device
viewport
browser
os
language
client_timezone
color_scheme
connection
traffic_source
referrer_domain
hour
weekday

重点是没有保存什么。

referrer 只保存 domain,不保存完整 URL。User-Agent 不保存原文,只分类为 browser、OS、device。IP 不保存。

这不是严格的数据仓库,而是个人公开博客用的流量面板。

今天、月份、全部、指定期间

一开始只想到和现有计数器一样的 今天 / 月 / 总

但统计页需要看具体日期和期间。

/analytics API 支持:

/analytics?range=today
/analytics?range=month
/analytics?range=total
/analytics?range=custom&start=2026-06-09&end=2026-06-12

这里的 total 是从 analytics_daily_dimensions 开始收集的 2026-06-09 之后的详细聚合,不是侧边栏里包含 GA baseline 的总浏览量。

这两个意义没有混在一起。

先保证手机上能用

统计页面在手机上很容易崩。

大表格会马上变得拥挤。所以我没有做大表,而是做成条形列表卡片。

顶部只放四个数字。

选择期间
今天
本月
全部

下面是各维度的卡片。

手机上,期间按钮折成两行,KPI 是两列,详细卡片是一列。自定义日期输入也纵向排列。

桌面上,KPI 保持一行,详细卡片展开为两列。

浏览器检查时没有横向 overflow,也没有 console error。

确认过的内容

检查如下。

node --check cloudflare/ga-stats-worker.js
node --check assets/js/custom/visitor-stats.js
node --check assets/js/custom/analytics-dashboard.js
bundle exec jekyll build
npx wrangler d1 execute hyuk-blog-view-counter --remote --file cloudflare/schema.sql
npx wrangler deploy --keep-vars

部署后,/analytics?range=today 正常返回。

新的聚合表还为空。这是正常的。详细 analytics 会从部署后的真实公开访问开始累积。

我也测试了本地 origin 的 tracking。

{"status":"ignored","reason":"origin_not_tracked"}

现在本地确认页面不会增加 production counter。

从访问计数器到公开 analytics

最初只是三个小数字。

今天、月、总。

但真正运营后,更重要的不是数字本身,而是数字是否干净。对于公开博客来说,比起隐藏私有日志,展示安全的聚合流向更合适。

这不是精确账本。

但现在至少能回答更多问题。

哪些文章被读了?

从哪些国家进来?

手机多还是桌面多?

是搜索、直接访问,还是 referral?

最重要的是,我自己的工作噪声该挡到什么程度?

这就是 /analytics/ 的用途。

留下评论