stats,每日聚合 stats_daily。接口本身公开(无需认证),但写入侧带服务端去重与频控。
读取计数
{ "likes": 0, "views": 0 }。响应头为 Cache-Control: public, s-maxage=60, stale-while-revalidate=300 + Cache-Tag: stats:<id>。
写入计数
响应(正常累加):
- 计数自增用 D1 原子 upsert(
ON CONFLICT DO UPDATE SET likes = MIN(likes + 1, 9999999)),并发点赞 / 浏览不会互相覆盖,单篇上限 9,999,999。 - 写入后回读最终计数再返回,响应里的数字总是库内真实值。
- 返回的
stats字段顺序是likes在前、views在后(JSON 对象本身无序,前端按字段名取值)。 - 点赞写入后会按
stats:<id>标签清边缘缓存;浏览是高频请求,不触发 purge,靠s-maxage=60自然过期。
趋势数据(管理后台)
days 取值被夹在 1 ~ 90(非数字或缺失时按 30 处理),返回连续的每日数据点(没有记录的日期补 0),可直接喂给仪表盘折线图。
响应:
no-store。
数据存储
stats 表(累计计数)
stats_daily 表(每日聚合)
每次点赞 / 浏览都会同步 upsert 一行
stats_daily(ON CONFLICT(post_id, date) DO UPDATE)。/api/stats/trend 就是对这张表按日期 SUM 聚合。
删除文章会连带删除
stats 计数,并尽力清理 stats_daily 的历史行;后者失败不阻断删除(聚合表属历史趋势数据,表缺失也允许)。详见文章 · 删除文章。KV 去重与频控键
去重标记与频控计数都存在 KV 绑定BLOG(不是 feed / sitemap / 文章缓存):
静态模式
mode: 'static' 下没有后端,阅读 / 点赞存在浏览器本地:
全部仅限本机,清缓存即丢失。详见配置说明。
来源与设备统计
浏览请求会同时累计stats_sources,用于仪表盘「来源 / 国家 / 设备」区域:
后台
GET /api/admin/stats/sources 返回近 30 天排行;仪表盘以国旗 + 占比展示,顶部 Top 榜与趋势图使用同一份数据。
