Insights / 技术解读

只用 Cloudflare 为 Astro 博客添加评论功能

不依赖外部评论服务,只使用 Cloudflare Pages Functions、D1、Turnstile 和 Wrangler 配置,为 Astro 博客实现评论功能的实践记录。

  • 技术
  • Cloudflare
  • Astro
  • 安全
  • 网站
只用 Cloudflare 为 Astro 博客添加评论功能
本文目录
  1. 结构
  2. 为什么使用 D1
  3. Wrangler 管理绑定
  4. Turnstile 必须服务端验证
  5. spam 对策
  6. SEO 与搜索
  7. 总结
  8. 参考

静态网站一旦需要评论功能,就会遇到状态保存和防 spam 的问题。

Acecore 没有引入外部评论 SaaS 或嵌入式 widget,而是在 PR #101 中用 Cloudflare 内的组件完成了实现。

  • Astro 显示评论 UI
  • Cloudflare Pages Functions 提供 /api/comments
  • Cloudflare D1 保存评论
  • Cloudflare Turnstile 保护投稿
  • wrangler.jsonc 定义 COMMENTS_DB binding

重点是:评论栏不是页面里的第三方孤岛,而是站点现有 Cloudflare 架构的一部分。

结构

实现范围很小。

文件或服务
UI src/components/BlogComments.astro
页面位置 src/views/BlogPostPage.astro
API functions/api/comments.ts
保存 D1 binding COMMENTS_DB
bot 对策 Cloudflare Turnstile
schema migrations/0001_create_blog_comments.sql

UI 通过 GET /api/comments?slug=...&locale=... 读取评论,并通过 POST /api/comments 投稿。

Pages Function 在写入前验证 origin、payload、Turnstile、rate limit、重复投稿和禁止内容。

为什么使用 D1

评论数据需要按文章查询、按时间排序、soft delete、重复检测和限流统计。D1 可以用 SQL 很直接地表达这些操作。

显示时只取 deleted_at IS NULL 的行。遇到 spam 时,不需要物理删除,只要给 deleted_at 写入时间即可隐藏。

查询使用 prepare(...).bind(...),避免把用户输入直接拼接到 SQL 里。

Wrangler 管理绑定

wrangler.jsonc 中定义 COMMENTS_DB

COMMENTS_DB 指向唯一的 D1 数据库 acecore-comments,这样 Cloudflare dashboard 和仓库中的数据库名称保持一致。

Cloudflare Pages 文档也说明,使用 Wrangler 配置时,它会成为 Pages project configuration 的 source of truth。

Turnstile 必须服务端验证

前端显示 Turnstile widget 只是第一步。

投稿时,Pages Function 会把 token 和 secret key 发送到 Cloudflare Siteverify API。验证结果成功后,才进入保存流程。

实现还会检查 Siteverify 返回的 hostname 是否在 allowlist 中。Cloudflare 的 Any Hostname 文档也要求在 server-side code 中验证 hostname。

spam 对策

第一版故意保持严格。

拒绝的内容包括:

  • URL
  • 邮箱地址
  • HTML 标签
  • Markdown 链接
  • 过度重复字符
  • 常见宣传词
  • honeypot 字段

限流也分两层:内存中的短期限流,以及 D1 中基于 client_hash 的持久限流。client_hash 使用 salt 后的 SHA-256,不保存原始 IP。

SEO 与搜索

评论区域标记为 data-pagefind-ignore,评论内容通过客户端读取。因此评论不会成为文章正文的一部分,也不会进入 Pagefind 索引。

企业博客中,正文是审核过的内容,评论是互动内容。两者分开管理更安全。

总结

外部评论服务很方便,但不是唯一选择。

如果网站已经运行在 Cloudflare Pages 上,那么 Pages Functions、D1、Turnstile 和 Wrangler 就足以构成一个轻量评论系统。

这样可以把 UI、数据、安全边界和基础设施配置都放在同一个 Cloudflare 运维模型中。

参考

Cloudflare Comments

仅使用Cloudflare构建评论功能的架构

Astro负责渲染UI,Cloudflare Pages Functions作为API边界,并将D1和Turnstile作为Cloudflare内部组件连接起来。

  1. 在Astro中放置UI

    在文章详情下方放置评论列表、投稿表单和Turnstile widget。

  2. 由Pages Function接收

    `/api/comments` 处理GET/POST/OPTIONS,并负责输入验证与CORS。

  3. 保存到D1

    通过 `COMMENTS_DB` binding将评论、hash和创建时间保存到兼容SQLite的D1。

  4. 用Turnstile保护

    在server-side validation Cloudflare Turnstile token,并检查hostname allowlist。

外部评论服务与Cloudflare自建方案的区别

外部评论服务

  • 导入速度快,但UI、数据存储位置、条款和显示速度都依赖服务方
  • 外部script或iframe容易影响文章页面的加载
  • 多语言UI和与网站设计统一时容易受到限制
  • 评论数据的处理、删除与迁移依赖服务规范

仅使用Cloudflare实现

  • 只用Pages Functions、D1和Turnstile即可拥有API与存储位置
  • 可作为Astro侧的HTML/CSS自然融入网站设计
  • 可通过Wrangler配置统一D1 binding与Cloudflare侧数据库名称
  • 可自行决定垃圾信息防护、删除流程和保存的个人信息范围

实现前需要决定的事项

  • 不把评论交给外部服务,而是在本网站的Cloudflare架构中管理
  • 以D1作为存储位置,以Cloudflare Pages Functions作为API边界
  • Turnstile token必须进行server-side validation
  • 在投稿前拒绝URL、邮箱、HTML、Markdown链接和宣传用语
  • 使D1 database名称与COMMENTS_DB binding和Cloudflare侧保持一致

常见问题

为什么不用外部评论服务?

外部服务导入很快,但 UI、数据保存、脚本加载、删除和迁移都会依赖服务方。这个实现把控制权留在网站和 Cloudflare 内。

D1 适合保存评论吗?

按 post_slug 查询、按 created_at 排序、soft delete、重复检测和速率限制都很适合用 D1 处理。

只在前端放 Turnstile 可以吗?

不可以。Pages Function 必须把 token 发送到 Cloudflare Siteverify,并在验证成功后再写入 D1。