Skip to main content
阅读与点赞都落在 D1 的两张表:累计计数 stats,每日聚合 stats_daily。接口本身公开(无需认证),但写入侧带服务端去重与频控。

读取计数

响应:
文章还没有任何计数时返回 { "likes": 0, "views": 0 }。响应头为 Cache-Control: public, s-maxage=60, stale-while-revalidate=300 + Cache-Tag: stats:<id>。

写入计数

请求体:
action 只接受 views 与 like(注意是 views 不是 view),其他值一律 400「action 只能是 views 或 like」。
响应(正常累加):
响应(命中去重,幂等不重复加):
  • 计数自增用 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 自然过期。
错误响应:

趋势数据(管理后台)

需会话 token。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 / 文章缓存):
KV 未绑定(env.BLOG 缺失)时,上表的去重与频控会静默失效——服务端只在日志里打一条 warning。存储数据仍写入 D1,功能不报错,但防刷能力消失。

静态模式

mode: 'static' 下没有后端,阅读 / 点赞存在浏览器本地: 全部仅限本机,清缓存即丢失。详见配置说明。

来源与设备统计

浏览请求会同时累计 stats_sources,用于仪表盘「来源 / 国家 / 设备」区域: 后台 GET /api/admin/stats/sources 返回近 30 天排行;仪表盘以国旗 + 占比展示,顶部 Top 榜与趋势图使用同一份数据。

文章分析与导出

后台「文章数据」页按文章聚合浏览量、点赞数、评论数与综合得分,支持全部 / 近 7 天 / 近 30 天范围、单篇趋势图与 CSV 导出;文章列表的统计不包含未发布文章的公开数据。