Skip to content

需求边界

前台只上报路径和 referrer,见 site/.vitepress/theme/track.ts。后台用口令拉汇总。不做实时大屏,前台也不渲染访问数字。

接口与模型

StatsController 挂在 /api

方法路径说明
POST/api/track上报一次浏览,成功 204
GET/api/stats/summary?key=汇总、30 日趋势、Top 页;口令错误 401,连续失败封禁 429

写入用 TrackRequest(path, referrer) 入参 DTO,持久化是 PageView 实体(pathreferrersourceip_hashcreated_at)。汇总形状是只读 Summary,不会把实体列表丢给浏览器。

隐私与限流

原始 IP 不入库。IpHasher 用当天日期加 IP_SECRET 做 HMAC-SHA256,次日哈希换盐,避免长期追踪。同一 ip_hash + path 30 秒内去重;按 IP 每分钟最多 60 次写入(RateLimiter)。summary() 进程内缓存 60 秒,单实例足够,查询不必每次扫全表细节。

口令来自环境变量 STATS_KEY,由 KeyGuard 对失败次数计数。密钥只在服务器 .env,不进 Git。

为什么自建

第三方脚本会把阅读行为送出站点,也很难写进「我如何设计接口」这种面试叙事。自建的代价是要自己做校验、去重和口令,这些代价有对应代码:StatsService.trackStatsController.summary

最后更新: