<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Dreamer</title><description>工科学生 · 学习笔记</description><link>https://blog.dogelover.online/</link><language>zh_CN</language><item><title>学 Cloudflare 第三轮：隧道、登录门、域名邮箱、外部数据库和私有网络</title><link>https://blog.dogelover.online/posts/cloudflare-learning-summary-3/</link><guid isPermaLink="true">https://blog.dogelover.online/posts/cloudflare-learning-summary-3/</guid><description>接着前两篇总结，这一轮我学了 Tunnel、Zero Trust Access、Email Routing、Hyperdrive、Containers 和 Workers VPC。有的已经上线（管理面板、域名邮箱、外部库演示），有的只摸清概念就停（Containers 要付费），全程还是没花一分钱。</description><pubDate>Sun, 11 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;/posts/cloudflare-learning-summary/&quot;&gt;第一轮总结&lt;/a&gt; 从 Pages、Workers、KV、D1、R2 写到工具页；&lt;a href=&quot;/posts/cloudflare-learning-summary-2/&quot;&gt;第二轮总结&lt;/a&gt; 写了 AI 搜索、Workflows、访问统计、AI 网关、分享封面和缩略图。10 月 11 日这一轮，话题从「在 Cloudflare 上干活」转到「怎么安全地接本机、收邮件、连外部数据库」：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tunnel&lt;/strong&gt;：本机服务不用公网 IP 也能被访问&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Zero Trust Access&lt;/strong&gt;：给管理页加「只有我能进」的邮箱登录门&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Email Routing&lt;/strong&gt;：&lt;code&gt;blog@dogelover.online&lt;/code&gt; 收到的信转到 Gmail&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hyperdrive&lt;/strong&gt;：Worker 连外部 Postgres 的连接池演示&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Containers&lt;/strong&gt;：能跑完整 Docker，但免费版用不了，只留了示例&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Workers VPC / 私有网络&lt;/strong&gt;：让 Worker 去调你家电脑上的服务（概念 + 材料）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;每个功能仍然按同样的顺序写：&lt;strong&gt;一句话说它是什么 → 我做了什么 / 现在到哪一步 → 一个关键概念 → 免费额度和费用&lt;/strong&gt;。&lt;/p&gt;
&lt;h2&gt;1. Cloudflare Tunnel：本机接到公网&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;一句话&lt;/strong&gt;：在你电脑上跑一个小程序 &lt;code&gt;cloudflared&lt;/code&gt;，它主动连到 Cloudflare；别人访问一个公网 HTTPS 地址时，请求再钻回你本机。不用公网 IP，也不用在路由器上开端口。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;我做了什么&lt;/strong&gt;：在学习环境里搭了中文演示页，也申请过临时的 &lt;code&gt;*.trycloudflare.com&lt;/code&gt; 地址。那段网络拦了 &lt;code&gt;cloudflared&lt;/code&gt; 连边缘节点，所以公网那边没能完整跑通；演示材料和讲解都留着，完整体验需要在自己电脑上开。博客、短链接这些仍然适合 Workers——Tunnel 是给「程序必须跑在我电脑上」的场景用的。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;关键概念：主动连出去，而不是被动开门&lt;/strong&gt;。传统做法是路由器端口转发，等于在防火墙上开一个洞。Tunnel 反过来：本机主动打给 Cloudflare，「有人找我就转给我」。所以家里没公网 IP、运营商禁了入站端口，也能临时把本机网页给朋友看。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;免费额度&lt;/strong&gt;：Quick Tunnel（临时地址）和正式命名隧道本身都不按流量收费。Quick Tunnel 适合测试，关掉就失效；长期用要建命名隧道，并且&lt;strong&gt;域名 DNS 要和隧道在同一个 Cloudflare 账号&lt;/strong&gt;。我的域名在另一个账号，所以这一轮没有绑自定义域名。&lt;/p&gt;
&lt;h2&gt;2. Zero Trust Access：管理页的邮箱门卫&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;一句话&lt;/strong&gt;：Access 挡在应用前面，先确认「你是谁」，通过了才能进；认的是个人身份（比如邮箱一次性验证码），比共享访问码更能审计、也能单独踢人。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;我做了什么&lt;/strong&gt;：&lt;a href=&quot;https://dreamer-admin.dogedreamer000.workers.dev/&quot;&gt;管理面板 dreamer-admin&lt;/a&gt; 已经上线，并用 Access 锁上了。打开后会先跳到 Cloudflare 登录页，用我自己的邮箱收一次性验证码才能进。面板只读检查博客相关几个服务是不是活着，还有一个「受保护操作」占位按钮——点了只返回成功信息，不改配置、不发邮件。工具页&lt;a href=&quot;https://blog.dogelover.online/tools/#lab&quot;&gt;实验室&lt;/a&gt;里也加了入口；没登录的人点进去也看不到面板内容。&lt;/p&gt;
&lt;p&gt;中间踩过一个坑：登录成功后 Worker 把正常的用户令牌误判成了服务令牌，页面进得去却提示无权。修好鉴权逻辑后，用无痕窗口重新登录就通了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;关键概念：门卫在外面，业务在里面&lt;/strong&gt;。Access 拦的是「谁能碰到这个网址」；Worker 里还可以再校验登录令牌，不信任随便传来的邮箱头。它和 Turnstile（防机器人）、访问码（知道口令就能进）、Tunnel（把本机接到公网）解决的是不同问题，也可以叠着用。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;免费额度&lt;/strong&gt;：Zero Trust 免费计划大约 50 个用户，个人管理后台远够用。开通时控制台有时会让填付款方式，选 Free 不会扣款。我没开按用户加量、远程浏览器隔离之类的付费项。&lt;/p&gt;
&lt;h2&gt;3. Email Routing：域名邮箱转到 Gmail&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;一句话&lt;/strong&gt;：给自己的域名一个真正能收信的地址，比如 &lt;code&gt;blog@dogelover.online&lt;/code&gt;，收到的信再转到已经在用的 Gmail（或交给 Worker 处理）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;我做了什么&lt;/strong&gt;：在管理域名的那个 Cloudflare 账号里，把 Gmail 加成目标邮箱并完成验证，再建自定义地址 &lt;code&gt;blog@dogelover.online&lt;/code&gt;，动作选转到 Gmail。我从自己的 grokbot 邮箱发了试信，第二封已经出现在 Gmail 收件箱——整条链路通了。对外可以用更正规的域名邮箱，对内还是用熟悉的 Gmail 收。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;关键概念：收信规则跟域名走，不跟 Workers 账号走&lt;/strong&gt;。我的博客 Workers 在一个账号，域名在另一个账号。A 账号的 Email Routing 选不到 B 账号的 Worker，所以现在最省事的路是「转到 Gmail」，而不是「交给 Worker 自动处理」。以后如果域名迁到同一个账号，才方便让 Worker 直接读邮件。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;免费额度&lt;/strong&gt;：转到已验证的目标邮箱不收费；入站路由本身也在免费计划里。Catch-all（全部接收）要慎开，避免和别的邮箱服务抢信。我这次只建了一个自定义地址，没有改会破坏现有配置的东西。&lt;/p&gt;
&lt;h2&gt;4. Hyperdrive：连外部 Postgres 的加速层&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;一句话&lt;/strong&gt;：Worker 要连 Neon、Supabase 这类外部数据库时，Hyperdrive 在中间做连接池和查询缓存，少掉每次重新握手的时间。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;我做了什么&lt;/strong&gt;：&lt;a href=&quot;https://dreamer-hyper.dogedreamer000.workers.dev/&quot;&gt;dreamer-hyper&lt;/a&gt; 演示页上线了。打开能看笔记列表；写入要先过访问保护。它连的是一份免费的 Neon Postgres，中间隔着 Hyperdrive。博客上的留言板、限额这些&lt;strong&gt;继续用 D1 就够&lt;/strong&gt;，不需要换成外部库——学它是为了以后真有 Neon / RDS 时会用。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;关键概念：D1 和 Hyperdrive 不是二选一的对手&lt;/strong&gt;。D1 是 Cloudflare 自家的 SQLite，Worker 直接绑就能用；Hyperdrive 是给「已经长在外面的 Postgres / MySQL」加速的。博客工具链优先 D1；只有「数据本来就在外部库」才上 Hyperdrive。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;免费额度&lt;/strong&gt;：Workers 免费计划里就有 Hyperdrive，大约每天 10 万次查询，超额报错不扣钱。连接池和查询缓存不另收费。外部库本身另有各自的免费额度；演示用的临时库会过期，需要的话可以认领到 Neon 免费账号长期用。&lt;/p&gt;
&lt;h2&gt;5. Containers：完整 Docker，但要付费计划&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;一句话&lt;/strong&gt;：Containers 让 Worker 按需拉起一个完整的 Linux 容器（Docker 镜像），适合跑任意语言、比较吃 CPU、或必须有完整文件系统的程序。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;我做了什么&lt;/strong&gt;：&lt;strong&gt;没有部署，也没有开通付费&lt;/strong&gt;。官方写明只有 Workers Paid（大约每月 5 美元）才能用，免费版是 N/A。按一直不花冤枉钱的原则，我只留了示例代码和讲解，以后真要跑 Docker 再拿出来。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;关键概念：Worker 轻，Container 重&lt;/strong&gt;。普通 Worker 是轻量的 JavaScript / Wasm，启动快、便宜，但跑不了随便一个 Python / Go 原生程序。Containers 补的是这一块：Worker 当门，旁边再开一个真正的 Linux 环境干活，空闲后休眠。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;免费额度&lt;/strong&gt;：没有。免费替代对现在的需求够用——网页和 API 用 Workers，分享封面用已有的 Browser Rendering，缩图用图床，本机服务用 Tunnel。&lt;/p&gt;
&lt;h2&gt;6. Workers VPC / 私有网络：让 Worker 摸到内网&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;一句话&lt;/strong&gt;：Workers VPC（目前 beta）让边缘上的 Worker，通过 Tunnel 去访问跑在你电脑 / 家里 / 公司内网、公网根本打不到的服务。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;我做了什么&lt;/strong&gt;：把容易混淆的名字分开写进了学习材料，没有在线上强行搭一套完整链路。完整跑通要在自己电脑上开命名隧道，并在 Cloudflare 里配 VPC 绑定；我这边的网络仍可能拦 &lt;code&gt;cloudflared&lt;/code&gt;，所以这一项以概念和可跟做的步骤为主。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;关键概念：三种「私网」别混&lt;/strong&gt;。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;名字&lt;/th&gt;
&lt;th&gt;谁访问谁&lt;/th&gt;
&lt;th&gt;典型场景&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;公开 Tunnel&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;浏览器 → 本机网页&lt;/td&gt;
&lt;td&gt;给朋友临时看本机开发页&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Workers VPC&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Worker → 本机 / 内网服务&lt;/td&gt;
&lt;td&gt;边缘 API 去调家里的数据库或脚本&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;WARP-to-Tunnel&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;人（装了 WARP）→ 内网 IP&lt;/td&gt;
&lt;td&gt;人远程进公司内网，不是 Worker&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;另外，Worker 调 Worker 用的是 Service Bindings，那是 Cloudflare 内部互调，&lt;strong&gt;不是&lt;/strong&gt;连你家局域网。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;免费额度&lt;/strong&gt;：官方写明 VPC 在 beta 期间各档 Workers 套餐都能用、不另收费。Tunnel 本身也不按流量收。个人博客日常继续用 Workers 就够；只有「程序必须跑在家里，又要给边缘的 Worker 调用」才需要 VPC。&lt;/p&gt;
&lt;h2&gt;小抄：这一轮几个工具怎么选&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;工具&lt;/th&gt;
&lt;th&gt;适合干什么&lt;/th&gt;
&lt;th&gt;不适合干什么&lt;/th&gt;
&lt;th&gt;我的现状&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Tunnel&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;本机 / 家里服务临时或长期挂到 HTTPS&lt;/td&gt;
&lt;td&gt;纯静态站、无状态 API（用 Workers / Pages 更好）&lt;/td&gt;
&lt;td&gt;概念与材料就绪，完整演示要在自己电脑上&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Access&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;管理后台、内部工具，「只允许这些人」&lt;/td&gt;
&lt;td&gt;公开博客、防机器人（那是 Turnstile）&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://dreamer-admin.dogedreamer000.workers.dev/&quot;&gt;dreamer-admin&lt;/a&gt; 已上线&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Email Routing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;域名邮箱收信再转到 Gmail&lt;/td&gt;
&lt;td&gt;随便群发营销信（那是另一套出站能力）&lt;/td&gt;
&lt;td&gt;&lt;code&gt;blog@dogelover.online&lt;/code&gt; 已测通&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Hyperdrive&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Worker 访问已有的外部 Postgres / MySQL&lt;/td&gt;
&lt;td&gt;新项目的小表格数据（优先 D1）&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://dreamer-hyper.dogedreamer000.workers.dev/&quot;&gt;dreamer-hyper&lt;/a&gt; 演示已上线&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Containers&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;必须跑完整 Docker / 任意语言&lt;/td&gt;
&lt;td&gt;普通网页和轻量 API&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;未部署&lt;/strong&gt;（要 Workers Paid）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Workers VPC&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;边缘 Worker 调用内网服务&lt;/td&gt;
&lt;td&gt;只是给人看本机面板（Tunnel + Access 更简单）&lt;/td&gt;
&lt;td&gt;概念弄清，未强行上线&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;可以叠着用：例如 Tunnel 把本机服务接到 Cloudflare，前面再加 Access；或者 VPC 让 Worker 调内网，对外仍然只暴露一个 &lt;code&gt;*.workers.dev&lt;/code&gt;。&lt;/p&gt;
&lt;h2&gt;我是怎么把费用保持在 0 的&lt;/h2&gt;
&lt;p&gt;这一轮比前两轮更「碰边界」——有的功能要第二个账号、有的要本机常开、有的直接写明付费才能用。我仍然一分钱没花，做法是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;先查价格页，再动手&lt;/strong&gt;。Containers 一看免费版 N/A，立刻停，只留示例。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;付费开关一律不开&lt;/strong&gt;。Zero Trust 选 Free；Hyperdrive、Tunnel、Email Routing、VPC beta 都走免费路径。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;账号拆开也认账&lt;/strong&gt;。域名和 Workers 不在同一账号时，不强行为了「接 Worker 收邮件」去迁域名或开付费；先用转到 Gmail 这种零成本方案。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;本机演示可停就停&lt;/strong&gt;。Tunnel / VPC 依赖电脑在线，演示完关掉，不把长期暴露当默认。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;敏感入口用身份，不只用口令&lt;/strong&gt;。管理面板走 Access 邮箱登录；公开工具继续用 Turnstile、访问码和每日限额（见&lt;a href=&quot;/posts/cloudflare-learning-summary-2/&quot;&gt;第二轮&lt;/a&gt;）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;继续盯账单和提醒&lt;/strong&gt;。异常监控还在跑；12 月 1 日起日志计费规则变化的提醒也还在。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;这一轮的收获&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;「代码在哪跑」决定选哪条路&lt;/strong&gt;：在 Cloudflare 上 → Workers / Pages；必须在自己电脑上 → Tunnel（给人看）或 VPC（给 Worker 调）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;身份比共享口令更适合管理后台&lt;/strong&gt;：Access 认人，访问码认口令，Turnstile 认是不是机器人——三个问题别用同一个答案硬套。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;学不等于全上线&lt;/strong&gt;：Containers 这种明确要付费的，把概念和示例留好就够；个人博客用免费替代也能走很远。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;到这里，三轮下来从「把网页挂上网」走到了「AI、统计、安全门、域名邮箱和私有网络」。下一步还没定——可能把 Access 或 Email Routing 拆成更细的笔记，也可能歇一阵先把现有工具用熟。你要是也在跟，可以从 &lt;a href=&quot;/posts/cloudflare-learning-summary/&quot;&gt;第一轮&lt;/a&gt; 和 &lt;a href=&quot;/posts/cloudflare-learning-summary-2/&quot;&gt;第二轮&lt;/a&gt; 顺着看过来。&lt;/p&gt;
</content:encoded></item><item><title>Cloudflare 每日热点 2026-10-11：Workers 火焰图性能分析、MCP 服务器提供 Cloudflare Skills</title><link>https://blog.dogelover.online/posts/cf-daily-2026-10-11/</link><guid isPermaLink="true">https://blog.dogelover.online/posts/cf-daily-2026-10-11/</guid><description>今天两条：Workers 和 Durable Objects 支持按需 CPU/内存性能分析（火焰图）；Cloudflare API MCP 服务器开始通过 MCP 提供 Cloudflare Skills。</description><pubDate>Sun, 11 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;1. Workers 和 Durable Objects 可以按需抓火焰图了&lt;/h2&gt;
&lt;p&gt;Cloudflare 宣布 Workers 和 Durable Objects 支持&lt;strong&gt;按需 CPU 和内存性能分析&lt;/strong&gt;。在 Worker 的 Observability（可观测性）页里选 “Flamegraph”，设定采样时长、选择版本，点 Capture Profile，就能看到交互式火焰图：每个矩形是一次函数调用，越宽代表占用的 CPU 时间或内存越多。也可以下载 &lt;code&gt;.pprof&lt;/code&gt; 文件用其他工具分析，或者用命令行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cf workers versions profile latest \
  --worker-id &quot;dreamer-search&quot; \
  --duration-ms 5000 \
  --profile-type cpu &amp;gt; worker-cpu.pprof
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;和我们的关系：&lt;code&gt;dreamer-search&lt;/code&gt;、&lt;code&gt;dreamer-shot&lt;/code&gt; 这类比较“重”的 Worker，如果哪天 CPU 时间变长，可以用它找出最耗时的函数。注意官方说 Worker 需要&lt;strong&gt;有足够流量&lt;/strong&gt;才能采到样，我们的小流量 Worker 可能要先自己打一些请求。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;💰 &lt;strong&gt;费用提醒&lt;/strong&gt;：公告没有写性能分析本身是否收费。Workers 免费版每次请求有 CPU 时间上限，付费版按 CPU 时间计费；为了采样而大量压测会消耗请求数和 CPU 额度，压测前先算一下。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;来源：&lt;a href=&quot;https://blog.cloudflare.com/workers-on-demand-profiling/&quot;&gt;Introducing on-demand CPU and memory profiling with flamegraphs for Workers and Durable Objects&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;2. Cloudflare API MCP 服务器开始提供 Cloudflare Skills&lt;/h2&gt;
&lt;p&gt;10 月 10 日的更新日志：Cloudflare API 的 MCP 服务器（&lt;code&gt;https://mcp.cloudflare.com/mcp&lt;/code&gt;）现在通过 “Skills over MCP” 扩展提供 Cloudflare Skills。支持这个扩展的 MCP 客户端可以用 &lt;code&gt;skills/list&lt;/code&gt; 发现技能，再用 &lt;code&gt;skill://&amp;lt;名字&amp;gt;/&amp;lt;路径&amp;gt;&lt;/code&gt; 读取技能文件。&lt;/p&gt;
&lt;p&gt;和我们的关系：简单说就是 AI 助手连上 Cloudflare 的 MCP 服务器后，不只是能调 API，还能拿到官方写好的“操作说明书”，让 AI 帮你部署 Workers、配 D1 时更少踩坑。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;💰 &lt;strong&gt;费用提醒&lt;/strong&gt;：MCP 服务器背后是你账号的 Cloudflare API，AI 通过它创建的资源（R2 桶、D1、Workers AI 调用等）照常计费。授权时尽量给只读或最小权限。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;来源：&lt;a href=&quot;https://developers.cloudflare.com/changelog/post/2026-10-10-cloudflare-mcp-skills/&quot;&gt;Cloudflare API MCP server serves Cloudflare skills&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>Cloudflare 每日热点 2026-10-10：Deno 加入 Cloudflare、Clef 降价、Traces 计费预告</title><link>https://blog.dogelover.online/posts/cf-daily-2026-10-10/</link><guid isPermaLink="true">https://blog.dogelover.online/posts/cf-daily-2026-10-10/</guid><description>今天三条：Deno 团队加入 Cloudflare 推动 Workers/Durable Objects 自托管；Workers AI 上的 Clef-flash 降价并推出 Clef-omni；Cloudflare Traces 公测，12 月 1 日起启用新计费。</description><pubDate>Sat, 10 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;1. Deno 团队加入 Cloudflare：Workers 和 Durable Objects 要能自托管了&lt;/h2&gt;
&lt;p&gt;10 月 9 日，Ryan Dahl（Deno 作者）和 Kenton Varda 宣布 Deno 团队加入 Cloudflare，会把 Deno 的 celld 和 Workers 运行时 workerd 合并，目标是让 &lt;strong&gt;自托管 Workers 和 Durable Objects&lt;/strong&gt; 成为官方支持的方式。&lt;/p&gt;
&lt;p&gt;和我们的关系：我写的 &lt;code&gt;dreamer-counter&lt;/code&gt;（Durable Objects 计数器）等代码，将来有机会不改编程模型就跑在自己的机器上。现在就可以先试试开源的 workerd 本地运行。&lt;/p&gt;
&lt;p&gt;来源：&lt;a href=&quot;https://blog.cloudflare.com/deno-joins-cloudflare/&quot;&gt;Deno is joining Cloudflare&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;2. Workers AI：Clef-flash 降价，新增多模态 Clef-omni&lt;/h2&gt;
&lt;p&gt;同样在 10 月 9 日，Cloudflare 推出能输入音频和视频的 Clef-omni，并把 Clef-flash 输入价格从每百万 token $0.09 降到 $0.038，Clef 本身也变快了。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;💰 &lt;strong&gt;费用提醒&lt;/strong&gt;：Workers AI 有每日免费额度，超出按量计费。音频、图片会被换算成输入 token，多模态调用消耗可能远超纯文本。想在 &lt;code&gt;dreamer-ai&lt;/code&gt; 这类公开接口上试用，记得保留限流。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;来源：&lt;a href=&quot;https://blog.cloudflare.com/clef-faster-cheaper-multimodal/&quot;&gt;Introducing Clef-omni…&lt;/a&gt;、&lt;a href=&quot;https://blog.cloudflare.com/clef-decision-models/&quot;&gt;Introducing Clef&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;3. Cloudflare Traces 公测：请求全链路追踪，12 月起新计费&lt;/h2&gt;
&lt;p&gt;Traces 把追踪从 Workers 扩展到整条请求路径：安全规则、缓存决策、路由、Worker 执行、回源都能在一条 trace 里看到，并支持导出到 OpenTelemetry（OTLP）。后续还计划覆盖 Workflows、Queues。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;💰 &lt;strong&gt;费用提醒&lt;/strong&gt;：从 &lt;strong&gt;2026 年 12 月 1 日&lt;/strong&gt; 起，Traces 和 Workers Tracing 按“摄入的数据量 + 保留时长”计费。如果给 Worker 开了 tracing/observability，12 月前检查一下采样率。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;来源：&lt;a href=&quot;https://blog.cloudflare.com/cloudflare-tracing/&quot;&gt;Introducing Cloudflare Traces&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>学 Cloudflare 第二轮：AI 搜索、工作流、访问统计、AI 网关、分享封面和缩略图</title><link>https://blog.dogelover.online/posts/cloudflare-learning-summary-2/</link><guid isPermaLink="true">https://blog.dogelover.online/posts/cloudflare-learning-summary-2/</guid><description>接着上一篇总结，这一轮我学了 Vectorize、Workflows、Analytics Engine、AI Gateway、Browser Rendering 和 Cloudflare Images，给博客加了 AI 搜索、访问统计、分享封面和图片缩略图，还把所有公开接口加固了一遍。全程没花一分钱。</description><pubDate>Sat, 10 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;/posts/cloudflare-learning-summary/&quot;&gt;上一篇总结&lt;/a&gt; 写到 Pages、Workers、KV、D1、R2、Turnstile、Cron 和异常监控。之后我又学了 Queues 和 Durable Objects，把访客计数器放进了侧边栏。接着从 10 月 9 日晚上到 10 月 10 日，又学了 6 个新功能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Vectorize&lt;/strong&gt;：给博客做 AI 搜索&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Workflows&lt;/strong&gt;：做了一条投稿审核流水线&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Analytics Engine&lt;/strong&gt;：给博客加访问统计&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AI Gateway&lt;/strong&gt;：给 AI 调用加缓存&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Browser Rendering&lt;/strong&gt;：自动生成分享封面&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cloudflare Images&lt;/strong&gt;：给图床加缩略图&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;工具多了，口子也多了，所以我顺手把所有公开接口加固了一遍，还在 &lt;a href=&quot;https://blog.dogelover.online/tools/&quot;&gt;工具页&lt;/a&gt; 加了一块「实验室」，所有学习演示都能从那里打开。&lt;/p&gt;
&lt;p&gt;每个功能都按同样的顺序写：&lt;strong&gt;一句话说它是什么 → 我做了什么 → 一个关键概念 → 免费额度和费用&lt;/strong&gt;。&lt;/p&gt;
&lt;h2&gt;1. Vectorize + Workers AI：博客 AI 搜索&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;一句话&lt;/strong&gt;：Vectorize 是一个向量数据库，能按「意思」找相近的文字，而不只是比对字面。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;我做了什么&lt;/strong&gt;：&lt;a href=&quot;https://dreamer-search.dogedreamer000.workers.dev/&quot;&gt;AI 搜博客&lt;/a&gt;，工具页上也有入口。用大白话提问，比如「留言板用了什么数据库？」，它会先在我的文章里找到相关段落，再让 AI 根据这些段落回答，并在答案后面附上出处文章。我把所有文章切成了几十小段，每段 400～600 字。问博客里没写过的内容（比如天气），它会老实回答「博客里暂时没写到」，不会瞎编。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;关键概念：RAG（检索增强生成）&lt;/strong&gt;。大模型并不知道我博客里写了什么，直接问它很容易编答案。RAG 的做法是「先查资料，再回答」：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;建索引&lt;/strong&gt;：把每段文字交给向量模型，变成 1024 个数字（相当于这段话的「意思坐标」），存进 Vectorize。意思相近的两段话，坐标也挨得近。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;检索&lt;/strong&gt;：把问题也变成坐标，找出最接近的 5 段。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;生成&lt;/strong&gt;：把这 5 段原文和问题一起交给聊天模型，要求它只按原文回答，并标出处。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如果最相近的段落也不够像，就直接回答「没写到」，连聊天模型都不调用，既省额度，又不会瞎编。&lt;/p&gt;
&lt;p&gt;还踩了个小坑：&lt;strong&gt;Vectorize 的写入要排队&lt;/strong&gt;。重建索引的接口返回「成功」，只代表请求被收下了，新文章大约 5 分钟后才搜得到。现在每天的自动发文流程会等新文章真的搜得到了，才算这一步完成。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;免费额度&lt;/strong&gt;：免费版就包含 Vectorize。查询按「(向量数 + 查询次数) × 维度」计量，每月 3000 万；按我现在的文章量，每月大约能问 600 多次。存储能放约 4800 段 1024 维的向量。超额只会报错，不会扣钱。&lt;/p&gt;
&lt;h2&gt;2. Workflows：投稿审核流水线&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;一句话&lt;/strong&gt;：Workflows 用来跑多步骤的长任务，每一步都会存档，任务可以中途睡觉，也可以停下来等人点按钮。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;我做了什么&lt;/strong&gt;：&lt;a href=&quot;https://dreamer-flow.dogedreamer000.workers.dev/&quot;&gt;投稿审核演示&lt;/a&gt;。提交一段文字后，能实时看到它一步步往下走：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;保存投稿&lt;/li&gt;
&lt;li&gt;AI 审核并写摘要（失败会自动重试）&lt;/li&gt;
&lt;li&gt;睡 30 秒冷静期&lt;/li&gt;
&lt;li&gt;等人点「批准」或「驳回」（10 分钟没人点就自动驳回）&lt;/li&gt;
&lt;li&gt;记录结果&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如果 AI 判定是广告，就跳过 3、4 步直接驳回。我实测时故意让 AI 第一次失败，5 秒后它自动重试成功，然后正好睡满 30 秒，我点了批准，流程立刻跑完。投一条「加微信代购、月入十万」的广告，15 秒内就被驳回了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;关键概念：重放（replay）&lt;/strong&gt;。Workflow 睡醒后，Cloudflare 会把整段代码从头再跑一遍，但已经做完的步骤不会真的再执行，而是直接拿存档的结果。所以写数据库、发邮件这类「做一次就够」的操作，一定要放在 &lt;code&gt;step.do&lt;/code&gt; 里面，否则每重放一次就会再做一次。步骤名字也要固定，Cloudflare 靠名字认出「这一步做过了」。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;免费额度&lt;/strong&gt;：每天 3000 步，睡觉和等待都不算步数，也不占 CPU。我限制了每人每天 5 次、全站每天 30 次，一天最多用掉约 150 步，也就是额度的 5%。超额只会报错，不会扣钱。&lt;/p&gt;
&lt;h2&gt;3. Analytics Engine：博客访问统计&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;一句话&lt;/strong&gt;：Analytics Engine 专门用来记大量事件，再用 SQL 按天、按页面、按国家分组统计。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;我做了什么&lt;/strong&gt;：&lt;a href=&quot;https://dreamer-stats.dogedreamer000.workers.dev/&quot;&gt;访问统计面板&lt;/a&gt;。博客每打开一页就记一条，面板上能看到最近 7 天的每日浏览量、热门文章、访客国家、来源网站和设备类型。记录里不存 IP，爬虫也不算数。新的访问大约 1～2 分钟后出现在面板上，面板本身有 5 分钟缓存。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;关键概念：采样&lt;/strong&gt;。流量特别大时，Analytics Engine 不会每条都存，而是「存 1 条，记下它代表 N 条」。所以计数不能用 &lt;code&gt;COUNT()&lt;/code&gt;，要用 &lt;code&gt;SUM(_sample_interval)&lt;/code&gt; 把抽样补回来。个人博客的流量远到不了会被抽样的程度，但代码照正确的写法来。&lt;/p&gt;
&lt;p&gt;这也是它和侧边栏计数器的分工：&lt;strong&gt;访客总数要精确，继续用 Durable Objects 计；「哪篇最火、读者从哪来」这类分析问题，交给 Analytics Engine。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;免费额度&lt;/strong&gt;：免费版每天能写 10 万条、查 1 万次，数据保留 3 个月。官方写明它目前还没开始收费。面板每 5 分钟最多查一次，怎么刷都用不完。&lt;/p&gt;
&lt;h2&gt;4. AI Gateway：给 AI 调用加缓存&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;一句话&lt;/strong&gt;：AI Gateway 是放在程序和 AI 模型之间的一个中转站，能缓存、记录、限流每一次 AI 调用。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;我做了什么&lt;/strong&gt;：建了一个网关，AI 小助手和 AI 搜博客的模型调用现在都从它经过。代码几乎不用改，只是在调用模型时多传一个参数，指明走哪个网关。效果很明显：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;场景&lt;/th&gt;
&lt;th&gt;第一次&lt;/th&gt;
&lt;th&gt;再问一次（命中缓存）&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;翻译同一句话&lt;/td&gt;
&lt;td&gt;约 2.3 秒&lt;/td&gt;
&lt;td&gt;约 0.2 秒&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI 搜博客问同一个问题&lt;/td&gt;
&lt;td&gt;2 秒多&lt;/td&gt;
&lt;td&gt;约 0.3 秒&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;缓存时间按用途分开设：翻译缓存 7 天，搜博客的回答缓存 1 天，聊天每次内容都不同，所以不缓存。另外加了每分钟最多 60 次的限流，作为第二道保险。我还做了一个兜底：万一网关出问题，程序会自动改成直接调用模型，功能不会挂。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;关键概念：缓存键是「完整的请求」&lt;/strong&gt;。模型、接口、请求内容必须一模一样才算同一个请求，差一个字都不行。缓存也是「尽力而为」：第一次请求后紧接着 0.6 秒内再发一次，并没有命中，因为结果还没来得及写进缓存，隔几秒再发就稳定命中了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;免费额度&lt;/strong&gt;：日志、分析、缓存、限流这些核心功能都免费。命中缓存时不调用模型，也就不消耗 AI 额度。会收费或会吃额度的几项（调用第三方模型、Guardrails 内容审核、Logpush 日志推送）我都没开。12 月 1 日起日志的计费规则会变，到时我会再核对一次。&lt;/p&gt;
&lt;h2&gt;5. Browser Rendering：自动生成分享封面&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;一句话&lt;/strong&gt;：Browser Rendering 让 Worker 在 Cloudflare 那边开一个看不见界面的 Chrome，用来截图、生成 PDF 或抓取网页。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;我做了什么&lt;/strong&gt;：&lt;a href=&quot;https://dreamer-shot.dogedreamer000.workers.dev/&quot;&gt;分享封面生成器&lt;/a&gt;。现在把博客文章分享到微信、X 这些地方，会自动带一张封面图，上面有标题、简介和我的柴犬头像。封面本身就是一个 1200×630 的普通网页，用 CSS 排好版，再让浏览器截图，存进 R2。每篇只画一次：第一次大约 5 秒，之后直接读存好的图，只要 0.2～0.4 秒。每天自动发文时，新文章的封面也会顺手生成好。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;关键概念：浏览器按「开着的时间」计费&lt;/strong&gt;。用完必须马上关掉，不然它会空等 60 秒才自动关闭，这 60 秒全都算你的。所以关浏览器的代码写在 &lt;code&gt;finally&lt;/code&gt; 里，中途出错也会关。批量生成时只开一次浏览器连画 5 篇，一共用了 3.7 秒，平均每篇 0.3 秒左右。&lt;/p&gt;
&lt;p&gt;为了不被人拿来乱截别的网站，它只接受我博客的地址。我测了十几种坏输入（指向别的网站、内网地址、&lt;code&gt;javascript:&lt;/code&gt; 之类），全部被拒绝。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;免费额度&lt;/strong&gt;：每天 10 分钟浏览器时间，部署加测试一共才用了 16 秒左右。我还设了上限，一天用满 5 分钟就停。额度用完只会报错，第二天早上 8 点（北京时间）恢复，不会扣钱。&lt;/p&gt;
&lt;h2&gt;6. Cloudflare Images：图床自动缩图&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;一句话&lt;/strong&gt;：Cloudflare Images 能把图片缩小、转成 WebP 或 AVIF 这类更省流量的格式。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;我做了什么&lt;/strong&gt;：给 R2 图床加了缩略图。在图片地址后面加上 &lt;code&gt;?w=400&amp;amp;f=webp&lt;/code&gt; 这样的参数，就能拿到缩小并转好格式的版本。工具页的图床卡片上传后，会直接列出 200、400、800、1200 四种宽度的链接，可以一键复制成 Markdown。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;请求&lt;/th&gt;
&lt;th&gt;大小&lt;/th&gt;
&lt;th&gt;耗时&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;原图 PNG（1200×630 的封面图）&lt;/td&gt;
&lt;td&gt;353 KB&lt;/td&gt;
&lt;td&gt;0.17 秒&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;400 宽 WebP，第一次（现转）&lt;/td&gt;
&lt;td&gt;10 KB（小了 97%）&lt;/td&gt;
&lt;td&gt;0.91 秒&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;400 宽 WebP，第二次（读存好的）&lt;/td&gt;
&lt;td&gt;10 KB&lt;/td&gt;
&lt;td&gt;0.19 秒&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;关键概念：参数白名单&lt;/strong&gt;。宽度只允许固定的几档，格式也只有几种。如果允许任意宽度，别人用 w=1、w=2……w=5000 就能一下子刷光每月的免费转换次数。转好的图会存进 R2，同一种尺寸永远只转一次。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;免费额度&lt;/strong&gt;：免费版每月 5000 次不同的转换，超了只是新图转不出来，官方原话是免费版超额不收费。我自己卡在每月最多新建 1000 张缩略图，超限时直接显示原图，不会出现裂图。注意，Cloudflare Images 有两种用法：「把图存在 Cloudflare Images 里」要付费，「只做转换、图还放在自己的 R2 里」免费可用，我用的是后者。&lt;/p&gt;
&lt;h2&gt;7. 安全加固：把口子一个个补上&lt;/h2&gt;
&lt;p&gt;工具一多，能被别人乱用的地方也多了。我按「会不会花钱、会不会被滥用」排查了一遍，补了三类口子：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;演示按钮加访问码&lt;/strong&gt;：学习日报和异常监控的「手动跑一次」、发测试邮件的接口、访客计数器的「手动 +1」，以前谁都能点，现在必须先输访问码。第一次点会弹框让你输一次，之后浏览器会记住。侧边栏的访客计数和定时任务都不受影响。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;短链接加 Turnstile 人机验证&lt;/strong&gt;：防止别人借我的服务批量生成跳转到钓鱼网站的短链。&lt;code&gt;javascript:&lt;/code&gt;、内网地址这类危险网址也会被直接拒掉。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;每日次数上限&lt;/strong&gt;：短链接、AI 小助手、AI 搜博客共用一个 D1 数据库来计数。AI 小助手和 AI 搜博客每人每天 30 次，全站分别 300 次和 500 次，北京时间 0 点清零。计数只存打乱过（加盐哈希）的 IP，不存真实 IP。如果计数本身出错，就拒绝请求，宁严勿松。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;一个体会&lt;/strong&gt;：免费版额度用完一般只会报错，不会扣钱，但会让工具当天用不了，所以限流还是值得加。&lt;/p&gt;
&lt;h2&gt;8. 工具页「实验室」：一个入口找到所有演示&lt;/h2&gt;
&lt;p&gt;以前这些演示各有各的 workers.dev 地址，我自己都记不住。现在 &lt;a href=&quot;https://blog.dogelover.online/tools/#lab&quot;&gt;工具页的实验室&lt;/a&gt; 把它们集中在一起：Workflows 投稿审核、Queues 任务队列、访客计数器、Cron 学习日报、异常监控和分享封面生成器。异常监控那里只显示状态，不放操作按钮。&lt;/p&gt;
&lt;p&gt;到这里，工具页上的东西是这样分工的：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;工具&lt;/th&gt;
&lt;th&gt;用到的 Cloudflare 能力&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;短链接&lt;/td&gt;
&lt;td&gt;Workers + KV + Turnstile + D1 限流&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI 小助手&lt;/td&gt;
&lt;td&gt;Workers AI + AI Gateway + D1 限流&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI 搜博客&lt;/td&gt;
&lt;td&gt;Vectorize + Workers AI + AI Gateway + D1 限流&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;留言板&lt;/td&gt;
&lt;td&gt;D1 + Turnstile&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;图床&lt;/td&gt;
&lt;td&gt;R2 + Images + Turnstile + 访问码&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;访问统计&lt;/td&gt;
&lt;td&gt;Analytics Engine&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;分享封面&lt;/td&gt;
&lt;td&gt;Browser Rendering + R2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;实验室&lt;/td&gt;
&lt;td&gt;Workflows、Queues、Durable Objects、Cron 等演示&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;小抄：Queues、Workflows、Cron、Durable Objects 怎么选&lt;/h2&gt;
&lt;p&gt;这四个最容易搞混，我自己是这么区分的：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;工具&lt;/th&gt;
&lt;th&gt;适合干什么&lt;/th&gt;
&lt;th&gt;打个比方&lt;/th&gt;
&lt;th&gt;我的例子&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cron&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;到点自动跑一次&lt;/td&gt;
&lt;td&gt;闹钟：每天 8 点叫醒我，跑完就忘&lt;/td&gt;
&lt;td&gt;学习日报、异常巡检&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Queues&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;一大堆小任务排队慢慢处理，削峰&lt;/td&gt;
&lt;td&gt;邮筒：信一股脑扔进去，再一封封处理&lt;/td&gt;
&lt;td&gt;任务队列演示&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Durable Objects&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;全世界唯一一份、绝对准确的共享状态&lt;/td&gt;
&lt;td&gt;全球只有一个的计数器&lt;/td&gt;
&lt;td&gt;侧边栏访客数&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Workflows&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;多步骤、必须可靠跑完、中途可能要等很久的流程&lt;/td&gt;
&lt;td&gt;工单：每道工序盖章存档，中途能等人签字&lt;/td&gt;
&lt;td&gt;投稿审核&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;它们也可以组合使用：比如 Cron 每天定时触发，再开一个 Workflow 去慢慢跑完一整套流程。&lt;/p&gt;
&lt;h2&gt;我是怎么把费用保持在 0 的&lt;/h2&gt;
&lt;p&gt;这一轮新功能很多，但到现在一分钱都没花。我的做法是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;只用免费计划&lt;/strong&gt;。免费计划超额的结果是报错，不会自动扣钱。我用的这几个功能，官方文档都写明了这一点，每次动手前我都会先查一遍最新的价格页。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自己设的上限比官方额度低&lt;/strong&gt;。浏览器每天只用一半（5 分钟），缩略图每月只用五分之一（1000 张），Workflows 一天最多用 5%，AI 每天有次数上限。这样就算被人刷，也碰不到官方额度。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;会花钱的开关一律不开&lt;/strong&gt;。比如 AI Gateway 的 Guardrails、Logpush、第三方模型，Images 的付费存储。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;能缓存就缓存，能只做一次就只做一次&lt;/strong&gt;。AI 回答走网关缓存，封面和缩略图生成一次就存进 R2，统计面板缓存 5 分钟。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;R2 要格外小心&lt;/strong&gt;。它绑了付款方式，所以新东西往 R2 里存之前，我都会先算一下量。缩略图每张才 10 KB 左右，离 10 GB 的免费存储还很远。异常监控也一直在盯着用量。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;到点复查&lt;/strong&gt;。12 月 1 日起日志的计费规则会变，我设了提醒，到时再核对一次。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;这一轮的收获&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;AI 功能离不开「资料」和「缓存」&lt;/strong&gt;：RAG 让 AI 只说博客里有的内容，网关缓存让重复的问题又快又不花额度。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;异步要有耐心&lt;/strong&gt;：Vectorize 写入要排队，Analytics Engine 要等一两分钟才查得到，「请求成功」不等于「马上生效」。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;工具一多，先想清楚「谁能点」&lt;/strong&gt;：访问码、人机验证、次数上限都要加，最好在功能上线时一起加。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;下一步还没定。可能把其中某个功能拆成单独的详细笔记，也可能继续学新的。你要是也在学 Cloudflare，可以先从 &lt;a href=&quot;/posts/cloudflare-learning-summary/&quot;&gt;上一篇&lt;/a&gt; 的基础部分看起。&lt;/p&gt;
</content:encoded></item><item><title>最近一周 Cloudflare 动态速览：Artifacts、可观测性，以及我这种小白要注意的账单坑</title><link>https://blog.dogelover.online/posts/cloudflare-hotspot-2026-10/</link><guid isPermaLink="true">https://blog.dogelover.online/posts/cloudflare-hotspot-2026-10/</guid><description>结合官方 Changelog 和社区讨论，整理 Artifacts 开放测试、Workers 日志进自定义看板、OAuth Provider v1、后量子加密，以及「没有硬封顶」这类实用提醒；对照我这几天做的工具箱，说说哪些值得跟、哪些先别碰。</description><pubDate>Fri, 09 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;这几天我一边学 Cloudflare，一边把博客、短链接、AI 小助手、留言板、图床、定时任务和访客计数都搭起来了（总览见 &lt;a href=&quot;/posts/cloudflare-learning-summary/&quot;&gt;《这几天学 Cloudflare 做了什么》&lt;/a&gt;）。学完一轮，我又去翻了官方 Changelog 和 X 上的讨论，整理成一期「热点速览」——重点写&lt;strong&gt;和我这种个人站有关的事&lt;/strong&gt;，以及&lt;strong&gt;可能花钱的地方&lt;/strong&gt;。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这篇是草稿，先给自己看。文中链接都指向公开文档或公开帖子，不含任何密钥。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;1. Artifacts 开放测试：像 Git 一样的版本化文件系统&lt;/h2&gt;
&lt;p&gt;2026 年 10 月 1 日，Cloudflare 宣布 &lt;strong&gt;&lt;a href=&quot;https://developers.cloudflare.com/changelog/post/2026-10-01-artifacts-open-beta/&quot;&gt;Artifacts 进入 open beta&lt;/a&gt;&lt;/strong&gt;。一句话理解：它是一套「会说 Git 的版本化文件存储」，可以给每个项目、用户、会话单独开仓库；还能从 Worker 里用 binding 管理仓库、读文件、发仓库级 Git token，以及用 Workers Builds 把某个分支部署成 Worker / Preview。&lt;/p&gt;
&lt;p&gt;社区里有人把它比喻成「给 AI agent 用的 Git」——agent 频繁提交时，按操作次数计费会很敏感。官方说明：&lt;strong&gt;Artifacts 需要 Workers Paid&lt;/strong&gt;，并从 &lt;strong&gt;2026 年 10 月 14 日开始计费&lt;/strong&gt;。他们还办了一个「用 Workers + Artifacts 做下一代 GitHub」的比赛，截止日期也是 10 月 14 日。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;对我意味着什么：&lt;/strong&gt;&lt;br /&gt;
现在我的博客源码在 GitHub，自动发布用 GitHub Actions，已经够用。Artifacts 很酷，但属于「要付费计划才玩」的进阶能力，&lt;strong&gt;短期内不会跟&lt;/strong&gt;。等以后真有「很多小仓库 / agent 自动提交」的需求，再单独评估账单。&lt;/p&gt;
&lt;h2&gt;2. Workers 日志和链路可以进自定义看板了&lt;/h2&gt;
&lt;p&gt;10 月 2 日的 Changelog：&lt;a href=&quot;https://developers.cloudflare.com/changelog/post/2026-10-02-workers-observability-in-custom-dashboards/&quot;&gt;Workers Observability 的 Logs / Traces 可以放进 Custom Dashboards&lt;/a&gt;。也就是说，可以把 Worker 的调用量、错误等级、CPU / 墙钟时间，和 HTTP 流量、安全事件画在同一张图上，方便对照「是流量暴涨导致报错，还是 Worker 自己坏了」。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;对我意味着什么：&lt;/strong&gt;&lt;br /&gt;
我已经有一个每小时巡检的监控 Worker，异常会发邮件。官方看板更适合看趋势和对比。下一步可以考虑：打开 Workers Logs，做一张「错误率 + 请求量」的简单看板，和自己的巡检互补——&lt;strong&gt;看板看趋势，邮件看告警&lt;/strong&gt;。&lt;/p&gt;
&lt;h2&gt;3. Workers OAuth Provider 到了 v1（偏 MCP / 开放接口）&lt;/h2&gt;
&lt;p&gt;同日附近还有一条：&lt;a href=&quot;https://developers.cloudflare.com/changelog/post/2026-10-01-workers-oauth-provider-1x/&quot;&gt;Workers OAuth Provider 升到 v1&lt;/a&gt;。授权服务器和资源服务器可以拆成两个 Worker，用 Service Binding 校验 token，不用绕公网；并跟上了较新的 MCP 授权规范。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;对我意味着什么：&lt;/strong&gt;&lt;br /&gt;
我目前只有博客工具页和几个小 API，还没对外做「登录后调用」的开放接口。这条先记在本子上：以后若要把 AI 小助手或留言板做成「别人也能安全调用」的服务，再认真学。&lt;/p&gt;
&lt;h2&gt;4. Workers 开始支持后量子算法（实验开关）&lt;/h2&gt;
&lt;p&gt;官方博客：&lt;a href=&quot;https://blog.cloudflare.com/workers-ml-kem-ml-dsa-support/&quot;&gt;Workers 支持 ML-KEM / ML-DSA 等现代 Web Crypto 算法&lt;/a&gt;（需兼容性 flag &lt;code&gt;webcrypto_modern_algorithms&lt;/code&gt;）。对个人博客几乎无感，但说明边缘运行时在跟着密码学标准往前走——以后写涉及密钥交换、签名的 Worker，可以少自己塞一套第三方 crypto。&lt;/p&gt;
&lt;h2&gt;5. 社区里反复出现的提醒：没有「硬封顶」&lt;/h2&gt;
&lt;p&gt;X 上最近有不少人在聊 Cloudflare 全家桶（Workers / Pages / D1 / R2 / Durable Objects / Workflows），也有人被账单吓到后提醒：&lt;strong&gt;Cloudflare 很多付费产品没有硬性花费上限&lt;/strong&gt;，超额会按量继续扣。有开发者分享了一段「让 AI 助手帮你检查是否开了账单预算提醒、看最近用量」的提示词思路（例如 &lt;a href=&quot;https://x.com/merill/status/2108140969552208074&quot;&gt;这条讨论&lt;/a&gt;）。&lt;/p&gt;
&lt;p&gt;另一类常见观点是：Cloudflare 已经从「基建极客玩具」变成更容易推荐给独立开发者的默认栈——前端 + 后端 + 数据库 + 对象存储都能在同一家搞定（例如 &lt;a href=&quot;https://x.com/ibocodes/status/2108213655548379468&quot;&gt;这类总结帖&lt;/a&gt;）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;对照我自己已经做的防护：&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;点&lt;/th&gt;
&lt;th&gt;我现在的做法&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;R2 图床（绑过卡，超额可能扣费）&lt;/td&gt;
&lt;td&gt;上传加了访问口令 + Turnstile&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Workers AI / 免费额度&lt;/td&gt;
&lt;td&gt;超额通常会报错而不是偷偷扣费；监控会看健康状态&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;账单预警&lt;/td&gt;
&lt;td&gt;建议在 Cloudflare Billing 里打开用量 / 超额邮件（官方渠道最稳）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;自己巡检&lt;/td&gt;
&lt;td&gt;每小时检查博客和各个 Worker，异常发 Gmail&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;官方定价和免费额度可以随时查：&lt;a href=&quot;https://developers.cloudflare.com/workers/platform/pricing/&quot;&gt;Workers Pricing&lt;/a&gt;、&lt;a href=&quot;https://developers.cloudflare.com/workers/platform/limits/&quot;&gt;Workers Limits&lt;/a&gt;。免费版 Workers 大致是每天 10 万次请求、单次约 10 ms CPU；超出后请求失败，而不是自动升级扣费——&lt;strong&gt;但一旦开了 Paid / 绑了卡的按量产品（比如 R2），逻辑就不一样了&lt;/strong&gt;。&lt;/p&gt;
&lt;h2&gt;6. 和我刚学过的 Queues、Durable Objects 对上号&lt;/h2&gt;
&lt;p&gt;这两天我还亲手试了：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Queues&lt;/strong&gt;：网页先把任务丢进队列，后台慢慢处理（演示站 dreamer-queue）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Durable Objects&lt;/strong&gt;：边缘上的「有状态小房间」，做了访客计数，并挂进博客侧边栏（按天去重）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;社区文档里也反复强调类似分工（例如 &lt;a href=&quot;https://developers.cloudflare.com/durable-objects/best-practices/rules-of-durable-objects/&quot;&gt;Durable Objects 使用原则&lt;/a&gt;）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;KV&lt;/strong&gt;：读多写少的配置 / 缓存（我的短链接）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D1&lt;/strong&gt;：表格型数据、要排序查询（留言板）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;R2&lt;/strong&gt;：文件和图片（图床）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Queues&lt;/strong&gt;：异步、可重试的后台活（发信、压图、批量处理）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Durable Objects&lt;/strong&gt;：需要强一致、按实体协调的状态（计数器、房间、协作）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Queues 消费者要按「至少投递一次」来写，同一条消息可能收到两次，处理逻辑最好做成幂等。Durable Objects 也不适合拿「整个网站一个全局房间」扛所有流量，更适合按用户 / 房间 / 文档拆开。&lt;/p&gt;
&lt;h2&gt;7. 这期我打算跟进什么、不跟进什么&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;可以跟（成本低、和现有站点相关）：&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;打开 Workers Observability，做一张简单错误率看板&lt;/li&gt;
&lt;li&gt;继续保持账单提醒 + 自己的巡检邮件&lt;/li&gt;
&lt;li&gt;若写下一篇专题，可以讲「Queues 消费者如何做成幂等」&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;先不跟（要 Paid 或偏远）：&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Artifacts（Paid + 10 月 14 日起计费）&lt;/li&gt;
&lt;li&gt;完整 MCP OAuth 拆分架构（暂时用不上）&lt;/li&gt;
&lt;li&gt;后量子算法实验（除非以后真有加密协议需求）&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;参考链接&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developers.cloudflare.com/changelog/post/2026-10-01-artifacts-open-beta/&quot;&gt;Artifacts is now in open beta&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developers.cloudflare.com/changelog/post/2026-10-02-workers-observability-in-custom-dashboards/&quot;&gt;Workers Observability in Custom Dashboards&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developers.cloudflare.com/changelog/post/2026-10-01-workers-oauth-provider-1x/&quot;&gt;Workers OAuth Provider v1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.cloudflare.com/workers-ml-kem-ml-dsa-support/&quot;&gt;Modern cryptographic algorithms in Workers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developers.cloudflare.com/workers/platform/pricing/&quot;&gt;Workers Pricing&lt;/a&gt; · &lt;a href=&quot;https://developers.cloudflare.com/workers/platform/limits/&quot;&gt;Limits&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developers.cloudflare.com/durable-objects/best-practices/rules-of-durable-objects/&quot;&gt;Rules of Durable Objects&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;社区讨论示例：&lt;a href=&quot;https://x.com/merill/status/2108140969552208074&quot;&gt;账单提醒提示词&lt;/a&gt;、&lt;a href=&quot;https://x.com/ibocodes/status/2108213655548379468&quot;&gt;Cloudflare 栈推荐&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;下一期如果继续做「热点博客」，我可以改成更固定的格式：每周挑 3～5 条官方更新 + 1～2 条社区技巧，对照我自己的小工具写「跟 / 不跟」。你觉得这篇可以发的话，把 &lt;code&gt;draft: true&lt;/code&gt; 改成 &lt;code&gt;false&lt;/code&gt; 再推送就行。&lt;/p&gt;
</content:encoded></item><item><title>这几天学 Cloudflare 做了什么：从个人主页到工具全家桶</title><link>https://blog.dogelover.online/posts/cloudflare-learning-summary/</link><guid isPermaLink="true">https://blog.dogelover.online/posts/cloudflare-learning-summary/</guid><description>从 Pages 搭博客开始，一路做到 Workers、KV、Workers AI、D1、R2、Turnstile、定时任务和异常监控；再把它们整合进工具页，并接上 GitHub 自动发布和自定义域名。这篇是总览。</description><pubDate>Fri, 09 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;这几天我把 Cloudflare 的几块核心能力挨个摸了一遍，顺手做出了一个能用的小工具集合。现在它们都挂在博客的 &lt;a href=&quot;https://blog.dogelover.online/tools/&quot;&gt;工具页&lt;/a&gt; 上，博客本身也换成了自己的域名 &lt;a href=&quot;https://blog.dogelover.online/&quot;&gt;blog.dogelover.online&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;这篇是总览：按时间顺序把「学了什么、做出了什么」串起来。细节可以点进下面链接的专题文章。&lt;/p&gt;
&lt;h2&gt;1. Pages：先把网站挂上网&lt;/h2&gt;
&lt;p&gt;起点很简单：用 &lt;strong&gt;Cloudflare Pages&lt;/strong&gt; 发布静态网站。Pages 会把 HTML / CSS / 图片分发到全球机房，自动配好 HTTPS。&lt;/p&gt;
&lt;p&gt;我先上传了一个很朴素的个人主页，后来换成 &lt;a href=&quot;https://github.com/saicaca/fuwari&quot;&gt;Fuwari&lt;/a&gt; 博客模板（基于 Astro），于是有了现在的博客。第一次发布的过程写在 &lt;a href=&quot;/posts/cloudflare-pages-homepage/&quot;&gt;《用 Cloudflare Pages 搭建个人主页》&lt;/a&gt; 里。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;一句话&lt;/strong&gt;：Pages 负责「把已经做好的网页放到全世界都能访问的地方」。&lt;/p&gt;
&lt;h2&gt;2. Workers：让网站能「干活」&lt;/h2&gt;
&lt;p&gt;静态页面无法自己生成短链接、调用 AI、读写数据库。这些要靠 &lt;strong&gt;Workers&lt;/strong&gt;：一段跑在 Cloudflare 边缘机房里的 JavaScript。有人访问网址时，离他最近的机房会执行这段代码并返回结果。&lt;/p&gt;
&lt;p&gt;我做的第一个 Worker 相关项目，是短链接和 AI 小助手，详见 &lt;a href=&quot;/posts/workers-shortlink-and-ai/&quot;&gt;《用 Cloudflare Workers 做了两个小工具》&lt;/a&gt;。&lt;/p&gt;
&lt;h2&gt;3. KV 短链接：键值存储&lt;/h2&gt;
&lt;p&gt;短链接需要把「短码 → 长网址」存起来，还要统计点击次数。这里用的是 &lt;strong&gt;Workers KV&lt;/strong&gt;：一种简单的键值存储，读写很快，适合这种「一个 key 对应一个 value」的场景。&lt;/p&gt;
&lt;p&gt;现在在工具页里可以生成短链、复制链接、查看点击次数。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;和数据库的差别&lt;/strong&gt;：KV 像字典；后面讲的 D1 更像表格。&lt;/p&gt;
&lt;h2&gt;4. Workers AI：边缘上的模型&lt;/h2&gt;
&lt;p&gt;第二个小工具是 &lt;strong&gt;AI 小助手&lt;/strong&gt;：中英互译 + 简单问答。模型跑在 Cloudflare 的 &lt;strong&gt;Workers AI&lt;/strong&gt; 上，Worker 里绑定一个 &lt;code&gt;AI&lt;/code&gt;，调用时指定模型名称即可。&lt;/p&gt;
&lt;p&gt;免费计划有每日 Neurons 额度；用完当天会报错，而不是偷偷扣费。试用时记得控制一下频率。&lt;/p&gt;
&lt;h2&gt;5. CORS + 工具页：把小工具塞进博客&lt;/h2&gt;
&lt;p&gt;博客在 &lt;code&gt;blog.dogelover.online&lt;/code&gt;，各个 Worker 却各自有 &lt;code&gt;*.workers.dev&lt;/code&gt; 网址。浏览器默认不允许网页随便调用其他域名的接口，这就是 &lt;strong&gt;跨域（CORS）&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;解决办法是在 Worker 里写一份允许名单，只放行博客域名（以及本地测试地址）。别人就算抄走页面代码，也调不动这些接口。&lt;/p&gt;
&lt;p&gt;整合之后，短链接和 AI 都出现在 &lt;a href=&quot;https://blog.dogelover.online/tools/&quot;&gt;工具页&lt;/a&gt; 里，样式跟博客统一，手机上也能用。&lt;/p&gt;
&lt;h2&gt;6. GitHub Actions：推送即发布&lt;/h2&gt;
&lt;p&gt;一开始改博客要：本地构建 → 打 zip → 控制台上传。后来我把源码放进 GitHub 私有仓库，用 &lt;strong&gt;GitHub Actions&lt;/strong&gt; 在推送到 &lt;code&gt;main&lt;/code&gt; 时自动构建，再上传到 Pages。&lt;/p&gt;
&lt;p&gt;密钥只给了「发布 Pages」所需的最小权限。过程写在 &lt;a href=&quot;/posts/github-actions-auto-deploy/&quot;&gt;《告别手动上传：用 GitHub Actions 自动发布博客》&lt;/a&gt; 里。你现在看到的文章，也是这样发上来的。&lt;/p&gt;
&lt;h2&gt;7. 自定义域名：blog.dogelover.online&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;*.pages.dev&lt;/code&gt; 可以一直免费用。我已经有域名 &lt;code&gt;dogelover.online&lt;/code&gt;，就加了子域名 &lt;strong&gt;blog&lt;/strong&gt;，在 Cloudflare Pages 里绑定自定义域名，再在管理该域名的账号里加一条 CNAME，指向 Pages 项目。&lt;/p&gt;
&lt;p&gt;几分钟后 HTTPS 证书签好，&lt;a href=&quot;https://blog.dogelover.online/&quot;&gt;blog.dogelover.online&lt;/a&gt; 就能打开。原来的 &lt;code&gt;dreamer-home.pages.dev&lt;/code&gt; 也还在。站点配置和 RSS 订阅地址也改成了新域名。&lt;/p&gt;
&lt;h2&gt;8. D1 留言板：边缘上的 SQLite&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;D1&lt;/strong&gt; 是 Cloudflare 上的 SQLite 数据库：数据像表格一样按行存，用 SQL 查询，适合留言、计数这类「多行记录、要排序」的场景。&lt;/p&gt;
&lt;p&gt;我做了一个简单留言板：访客写名字和内容，存在 D1 里，刷新就能看到。和 KV 不同，这里用的是 &lt;code&gt;SELECT&lt;/code&gt; / &lt;code&gt;INSERT&lt;/code&gt;，而不是单纯的 get / put。&lt;/p&gt;
&lt;p&gt;留言板同样挂在 &lt;a href=&quot;https://blog.dogelover.online/tools/&quot;&gt;工具页&lt;/a&gt; 底部。&lt;/p&gt;
&lt;h2&gt;9. R2 图床：对象存储&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;R2&lt;/strong&gt; 是对象存储，适合放大文件和图片（按「一个文件一个对象」来存）。开通时需要绑定支付方式，套餐本身可以是 $0/月，免费额度对个人图床通常够用；超额才会计费。&lt;/p&gt;
&lt;p&gt;图床 Worker 负责上传和按链接读取；桶本身不公开，必须走 Worker，这样更安全。传完会得到一个可直接引用的图片链接。入口也在工具页的「图床」区块。&lt;/p&gt;
&lt;p&gt;后来我又加了可选的 &lt;strong&gt;访问码&lt;/strong&gt;（Worker 机密 &lt;code&gt;ACCESS_CODE&lt;/code&gt;）：开启后上传必须带正确口令，工具页会把口令记在浏览器本地，减少陌生访客直接往 R2 塞文件、踩免费额度或产生超额费用的风险。&lt;/p&gt;
&lt;h2&gt;10. Turnstile：挡一下机器人&lt;/h2&gt;
&lt;p&gt;留言板和图床谁都能用，容易被刷。我给这两项加了 &lt;strong&gt;Cloudflare Turnstile&lt;/strong&gt;：一种比传统验证码更省事的人机验证，访客点一下或后台自动过关即可。&lt;/p&gt;
&lt;p&gt;没有通过验证的请求会被接口拒绝。短链接和 AI 风险相对小，暂时没加。&lt;/p&gt;
&lt;h2&gt;11. Cron：到点自动跑&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Cron Triggers&lt;/strong&gt; 相当于给 Worker 定闹钟。到点 Cloudflare 会自动调用一次，不用等人访问网址。&lt;/p&gt;
&lt;p&gt;我做了一个定时任务：每天北京时间上午 9 点，自动往留言板写一条「学习日报」。状态页上还能看到上次运行时间，也可以手动再跑一次。免费账号大约能配几个定时器，对个人项目够用。&lt;/p&gt;
&lt;h2&gt;12. 异常监控：每小时巡检 + 邮件&lt;/h2&gt;
&lt;p&gt;工具多了之后，我想早点知道「哪个挂了」，尤其是绑了卡的 R2。于是做了 &lt;strong&gt;dreamer-watch&lt;/strong&gt;：用 Cron 每小时跑一轮，用 Cloudflare API 确认各 Worker 脚本还在，再用 HTTP 检查博客首页和工具页；异常时通过 Resend 发中文邮件到我的 Gmail。&lt;/p&gt;
&lt;p&gt;状态页可以看到上次巡检结果和连续失败次数。邮件用 &lt;code&gt;onboarding@resend.dev&lt;/code&gt; 发就够个人告警；告警本身不能替代你在 Cloudflare 账单页自己设用量提醒。&lt;/p&gt;
&lt;h2&gt;现在工具页里有什么&lt;/h2&gt;
&lt;p&gt;打开 &lt;a href=&quot;https://blog.dogelover.online/tools/&quot;&gt;blog.dogelover.online/tools/&lt;/a&gt; 可以看到：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;工具&lt;/th&gt;
&lt;th&gt;用到的 Cloudflare 能力&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;短链接&lt;/td&gt;
&lt;td&gt;Workers + KV&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI 小助手&lt;/td&gt;
&lt;td&gt;Workers + Workers AI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;留言板&lt;/td&gt;
&lt;td&gt;Workers + D1 + Turnstile&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;图床&lt;/td&gt;
&lt;td&gt;Workers + R2 + Turnstile + 访问码&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;（幕后）学习日报&lt;/td&gt;
&lt;td&gt;Workers + Cron + D1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;（幕后）异常监控&lt;/td&gt;
&lt;td&gt;Workers + Cron + D1 + Resend&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;博客本身：Pages + GitHub Actions 自动发布 + 自定义域名。&lt;/p&gt;
&lt;h2&gt;这几天最大的收获&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;先能跑，再学深&lt;/strong&gt;：Pages 挂上网 → Workers 干点活 → 再学存储和防护，比一开始啃文档有效。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;选对存储&lt;/strong&gt;：键值用 KV，表格用 D1，大文件用 R2，别硬套。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;跨域和权限要认真&lt;/strong&gt;：白名单、最小权限 Token、Turnstile，都是「能用」变成「能安心用」的关键。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自动化很爽&lt;/strong&gt;：推送到 GitHub 就能发布，改文章的心理负担小了很多。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;接下来可能把 R2、Turnstile、Cron、监控拆成更细的笔记，或者给短链接、AI 也加一点限流。你要是也在学 Cloudflare，欢迎从 Pages 开始，做点小东西，比只看书记得牢。&lt;/p&gt;
</content:encoded></item><item><title>告别手动上传：用 GitHub Actions 自动发布博客到 Cloudflare Pages</title><link>https://blog.dogelover.online/posts/github-actions-auto-deploy/</link><guid isPermaLink="true">https://blog.dogelover.online/posts/github-actions-auto-deploy/</guid><description>把博客源码放进 GitHub 私有仓库，用 GitHub Actions + wrangler-action 实现“推送即发布”，顺便讲讲最小权限的 API Token 和构建重试。</description><pubDate>Fri, 09 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;之前每次改完博客，我都要：本地构建 → 把 &lt;code&gt;dist&lt;/code&gt; 目录打成 zip → 打开 Cloudflare 控制台 → 进 Pages 项目 → Create deployment → 上传。改一个错别字也要走一遍，实在有点累。&lt;/p&gt;
&lt;p&gt;现在换成了 &lt;strong&gt;GitHub + GitHub Actions 自动发布&lt;/strong&gt;：改完代码推到 GitHub，大约一分钟后网站就自己更新了。&lt;strong&gt;你现在看到的这篇文章，就是我推送到 &lt;code&gt;main&lt;/code&gt; 分支后自动发布上来的。&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;整体流程&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;我改代码 → git push 到 main
            ↓
GitHub Actions 在 GitHub 的服务器上：
  安装依赖 → 构建博客 → 用 wrangler 上传到 Cloudflare Pages
            ↓
blog.dogelover.online（以及 dreamer-home.pages.dev）更新
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;整个过程中，Cloudflare 那边什么都不用点，自定义域名 &lt;code&gt;blog.dogelover.online&lt;/code&gt; 和原来的 &lt;code&gt;dreamer-home.pages.dev&lt;/code&gt; 都会一起更新。&lt;/p&gt;
&lt;h2&gt;第一步：把源码放进 GitHub 私有仓库&lt;/h2&gt;
&lt;p&gt;我在 GitHub 上建了一个&lt;strong&gt;私有&lt;/strong&gt;仓库 &lt;code&gt;dreamer-home&lt;/code&gt;，把博客源码推了上去。私有的意思是只有我自己能看到源码，网站本身还是公开的。&lt;/p&gt;
&lt;p&gt;推之前我特意检查了一遍，&lt;strong&gt;仓库里不能有任何密码或密钥&lt;/strong&gt;。&lt;code&gt;node_modules&lt;/code&gt;、&lt;code&gt;dist&lt;/code&gt; 这类可以重新生成的目录也通过 &lt;code&gt;.gitignore&lt;/code&gt; 排除掉了。&lt;/p&gt;
&lt;h3&gt;小插曲：用设备码登录 GitHub CLI&lt;/h3&gt;
&lt;p&gt;我是在一台远程的 Linux 电脑上操作的，那里没法方便地打开浏览器登录。后来发现 GitHub 官方命令行工具 &lt;code&gt;gh&lt;/code&gt; 支持&lt;strong&gt;设备码登录&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gh auth login --web
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它会显示一个 8 位码，我在手机上打开 &lt;code&gt;github.com/login/device&lt;/code&gt;，输入这个码、点一下授权，那台电脑就登录好了。全程不用在电脑上输密码，很适合这种场景。&lt;/p&gt;
&lt;h2&gt;第二步：写 GitHub Actions 工作流&lt;/h2&gt;
&lt;p&gt;GitHub Actions 就是 GitHub 提供的“自动化流水线”。在仓库里放一个 &lt;code&gt;.github/workflows/deploy.yml&lt;/code&gt; 文件，告诉它“什么时候做、做什么”。这是我实际在用的文件：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;name: Deploy to Cloudflare Pages

on:
  push:
    branches: [main]      # 推送到 main 时自动运行
  workflow_dispatch:      # 也可以在 Actions 页面手动点一下运行

concurrency:              # 连续推送时，取消还没跑完的旧任务
  group: deploy-pages-${{ github.ref }}
  cancel-in-progress: true

permissions:
  contents: read          # 只需要读代码

jobs:
  deploy:
    runs-on: ubuntu-latest
    timeout-minutes: 20
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup pnpm
        uses: pnpm/action-setup@v4
        with:
          version: 9.14.4
          run_install: false

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: pnpm

      - name: Install dependencies
        run: pnpm install --frozen-lockfile

      # 偶尔出现一次性的 Tailwind 报错，失败时自动重试，最多 3 次
      - name: Build
        run: |
          for i in 1 2 3; do
            if pnpm build; then exit 0; fi
            echo &quot;::warning::Build attempt $i failed, retrying...&quot;
            sleep 5
          done
          exit 1

      - name: Deploy to Cloudflare Pages
        uses: cloudflare/wrangler-action@v3
        with:
          apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
          accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
          wranglerVersion: &quot;4&quot;
          command: pages deploy dist --project-name=dreamer-home --branch=main --commit-dirty=true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;几个值得说的地方：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;on.push.branches: [main]&lt;/code&gt;&lt;/strong&gt;：只有推到 &lt;code&gt;main&lt;/code&gt; 才发布。以后想先试验，可以在别的分支上改。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;pnpm install --frozen-lockfile&lt;/code&gt;&lt;/strong&gt;：严格按 &lt;code&gt;pnpm-lock.yaml&lt;/code&gt; 安装，保证 GitHub 上装的依赖版本和我本地一模一样。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;最后一步 &lt;code&gt;wrangler-action&lt;/code&gt;&lt;/strong&gt;：Cloudflare 官方提供的 Action，本质就是在 GitHub 的服务器上执行 &lt;code&gt;wrangler pages deploy dist&lt;/code&gt;，把构建好的 &lt;code&gt;dist&lt;/code&gt; 目录上传到我已有的 Pages 项目 &lt;code&gt;dreamer-home&lt;/code&gt;。效果和我之前手动上传 zip 一样，只是不用我动手了。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;为什么要“构建重试”&lt;/h3&gt;
&lt;p&gt;在本地构建时，我遇到过好几次：第一次 &lt;code&gt;pnpm build&lt;/code&gt; 报一个 Tailwind 相关的错误，什么都不改再跑一次就好了。这种“偶发失败”（flaky）如果放到自动发布里，就会出现“明明代码没问题，发布却失败了”的情况。&lt;/p&gt;
&lt;p&gt;所以我在 Build 这一步写了个小循环：失败了等 5 秒重试，最多 3 次，3 次都失败才真正算失败。这不是从根本上解决问题，但很实用。&lt;/p&gt;
&lt;h2&gt;第三步：最小权限的 API Token&lt;/h2&gt;
&lt;p&gt;GitHub 要往我的 Cloudflare 账号上传网站，就得有一把“钥匙”，也就是 &lt;strong&gt;Cloudflare API Token&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;这里我学到的最重要的一点是：&lt;strong&gt;给钥匙的时候，只给刚好够用的权限&lt;/strong&gt;。在 Cloudflare 控制台创建 Token 时，我没有用“全局 API Key”（那个能管整个账号），而是自定义了一个 Token，只勾了一项权限：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Account → Cloudflare Pages → Edit&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这样就算这个 Token 哪天不小心泄露了，别人最多也只能发布 Pages，动不了我的 Workers、KV、DNS 或者账单。&lt;/p&gt;
&lt;h3&gt;存成仓库 Secrets&lt;/h3&gt;
&lt;p&gt;Token 和账号 ID &lt;strong&gt;绝对不能直接写进 &lt;code&gt;deploy.yml&lt;/code&gt;&lt;/strong&gt;，否则就跟着代码一起进了仓库。正确做法是存到仓库的 &lt;strong&gt;Settings → Secrets and variables → Actions&lt;/strong&gt; 里：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;CLOUDFLARE_API_TOKEN&lt;/code&gt;：上面那个 Token&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CLOUDFLARE_ACCOUNT_ID&lt;/code&gt;：Cloudflare 账号 ID&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;工作流里用 &lt;code&gt;${{ secrets.XXX }}&lt;/code&gt; 引用它们。Secrets 存进去之后连我自己都看不到原值，在运行日志里也会被自动打码成 &lt;code&gt;***&lt;/code&gt;。&lt;/p&gt;
&lt;h2&gt;第四步：验证&lt;/h2&gt;
&lt;p&gt;一切配好后，我先在 Actions 页面手动点了一次 &lt;strong&gt;Run workflow&lt;/strong&gt;。大约一分钟，四个步骤全部打勾，刷新博客就看到了变化：侧边栏的 GitHub 按钮现在指向我的 GitHub 主页了。&lt;/p&gt;
&lt;p&gt;然后就是这篇文章：我在本地写好 Markdown，&lt;code&gt;git push&lt;/code&gt; 到 &lt;code&gt;main&lt;/code&gt;，剩下的全交给 GitHub Actions。如果你能读到这里，说明它成功了 🎉&lt;/p&gt;
&lt;h2&gt;小结&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;之前（手动上传）&lt;/th&gt;
&lt;th&gt;现在（自动发布）&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;发布步骤&lt;/td&gt;
&lt;td&gt;构建、打包、登录控制台、上传&lt;/td&gt;
&lt;td&gt;&lt;code&gt;git push&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;改一个错别字&lt;/td&gt;
&lt;td&gt;好几分钟&lt;/td&gt;
&lt;td&gt;推完等一分钟&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;历史记录&lt;/td&gt;
&lt;td&gt;没有&lt;/td&gt;
&lt;td&gt;每次改动都在 Git 里&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;出错排查&lt;/td&gt;
&lt;td&gt;靠记忆&lt;/td&gt;
&lt;td&gt;看 Actions 日志&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;这次学到的关键词：&lt;strong&gt;私有仓库&lt;/strong&gt;、&lt;strong&gt;GitHub Actions 工作流&lt;/strong&gt;、&lt;strong&gt;wrangler-action&lt;/strong&gt;、&lt;strong&gt;最小权限 Token&lt;/strong&gt;、&lt;strong&gt;仓库 Secrets&lt;/strong&gt;、&lt;strong&gt;构建重试&lt;/strong&gt;，还有 GitHub CLI 的&lt;strong&gt;设备码登录&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;下一步打算试试 Cloudflare 的 D1 数据库，给博客加个留言板或访问计数。&lt;/p&gt;
</content:encoded></item><item><title>用 Cloudflare Pages 搭建个人主页</title><link>https://blog.dogelover.online/posts/cloudflare-pages-homepage/</link><guid isPermaLink="true">https://blog.dogelover.online/posts/cloudflare-pages-homepage/</guid><description>零基础也能看懂：Cloudflare Pages 是什么、我是怎么用“直接上传”发布第一个网站的，以及接下来可以做什么。</description><pubDate>Thu, 08 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;这是我学习 Cloudflare 的第一篇笔记，记录一下怎么用 &lt;strong&gt;Cloudflare Pages&lt;/strong&gt; 免费发布一个个人主页。整个过程不用买服务器、不用配 Nginx，十几分钟就能拿到一个可以分享给别人的网址。&lt;/p&gt;
&lt;h2&gt;Cloudflare Pages 是什么&lt;/h2&gt;
&lt;p&gt;Cloudflare 在全球有几百个机房（数据中心）。&lt;strong&gt;Pages&lt;/strong&gt; 是它提供的静态网站托管服务：你把写好的 HTML、CSS、JavaScript 和图片交给它，它就会把这些文件复制到全球的机房里。访客打开网站时，会由离他最近的机房响应，所以速度很快。&lt;/p&gt;
&lt;p&gt;“静态网站”指的是页面内容在发布前就已经生成好的网站，比如个人主页、博客、作品集、项目文档。这个博客本身也是一个静态网站。&lt;/p&gt;
&lt;h2&gt;我是怎么发布的：直接上传&lt;/h2&gt;
&lt;p&gt;Pages 有两种发布方式：&lt;strong&gt;连接 Git 仓库&lt;/strong&gt;（推代码自动部署）和 &lt;strong&gt;直接上传&lt;/strong&gt;（Direct Upload）。第一次我选了最简单的直接上传，步骤如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;在本地写好网页，只有两个文件：&lt;code&gt;index.html&lt;/code&gt; 和 &lt;code&gt;style.css&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;把这两个文件打包成一个 zip 压缩包（注意 &lt;code&gt;index.html&lt;/code&gt; 要放在压缩包的最外层）&lt;/li&gt;
&lt;li&gt;登录 Cloudflare 控制台，进入 &lt;strong&gt;Workers 和 Pages&lt;/strong&gt;，点击 &lt;strong&gt;创建&lt;/strong&gt; → &lt;strong&gt;Pages&lt;/strong&gt; → &lt;strong&gt;上传资产&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;给项目起名 &lt;code&gt;dreamer-home&lt;/code&gt;，这个名字会成为网址的前缀&lt;/li&gt;
&lt;li&gt;上传 zip，点击 &lt;strong&gt;部署站点&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;几秒钟后，网站就上线了，地址是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://dreamer-home.pages.dev
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;后来又绑了自己的域名，现在主站是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://blog.dogelover.online
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;:::tip[小提示]
控制台网页一次只能选一个文件时，打包成 zip 再上传最省事。直接上传的限制是：单次最多 1000 个文件，单个文件不超过 25 MB。
:::&lt;/p&gt;
&lt;h2&gt;自动帮你做好的事情&lt;/h2&gt;
&lt;p&gt;发布之后，Cloudflare 默认就帮我做好了这些事，完全不用自己配置：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;HTTPS 加密&lt;/strong&gt;：自动签发证书，地址栏直接显示小锁&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;全球 CDN&lt;/strong&gt;：文件缓存在全球各地的机房，国内外访问都比较快&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;抗攻击&lt;/strong&gt;：网站躲在 Cloudflare 的网络后面，能挡住大部分恶意流量&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;版本记录&lt;/strong&gt;：每次部署都会保留一个版本，出问题可以一键回滚&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;免费额度&lt;/h2&gt;
&lt;p&gt;对个人学习来说，免费版基本用不完：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;项目&lt;/th&gt;
&lt;th&gt;免费额度&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;网站流量和请求&lt;/td&gt;
&lt;td&gt;不限&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;每月构建次数&lt;/td&gt;
&lt;td&gt;500 次&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;单个项目的自定义域名&lt;/td&gt;
&lt;td&gt;最多 100 个&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;单个文件大小&lt;/td&gt;
&lt;td&gt;25 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;:::note[注意]
Pages 的静态网站本身不收费；但如果以后用到 Workers、D1 数据库这类按量计费的功能，记得留意用量，Cloudflare 没有硬性的消费上限。
:::&lt;/p&gt;
&lt;h2&gt;下一步&lt;/h2&gt;
&lt;p&gt;直接上传适合第一次体验，但每次修改都要重新打包上传，有点麻烦。接下来我打算：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;连接 GitHub 自动部署&lt;/strong&gt;：把网站代码放到 GitHub 仓库，Pages 连接仓库后，每次 &lt;code&gt;git push&lt;/code&gt; 就会自动构建并发布&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;绑定自己的域名&lt;/strong&gt;：买一个便宜的域名，接入 Cloudflare 后绑定到这个项目&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;学习 Workers&lt;/strong&gt;：给网站加一点后端功能，比如访问计数或者留言板&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;学到哪里，就在这个博客里记录到哪里。&lt;/p&gt;
</content:encoded></item><item><title>用 Cloudflare Workers 做了两个小工具：短链接和 AI 小助手</title><link>https://blog.dogelover.online/posts/workers-shortlink-and-ai/</link><guid isPermaLink="true">https://blog.dogelover.online/posts/workers-shortlink-and-ai/</guid><description>第一次写 Workers：用 KV 做一个能计数的短链接，用 Workers AI 做一个中英互译 + 问答的小助手，最后通过 CORS 把它们整合进博客的工具页。</description><pubDate>Thu, 08 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;上一篇我用 Cloudflare Pages 发布了这个博客。Pages 只能放“提前做好的”静态网页，要让网站真的“干点活”（比如生成短链接、调用 AI），就要用到 &lt;strong&gt;Cloudflare Workers&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;这两天我用 Workers 做了两个小工具，现在都放在博客的 &lt;a href=&quot;https://blog.dogelover.online/tools/&quot;&gt;工具页&lt;/a&gt; 里，可以直接试用：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;短链接 dreamer-link&lt;/strong&gt;：把长网址变成短网址，还能看点击次数&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AI 小助手 dreamer-ai&lt;/strong&gt;：中英互译 + 简单问答&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下面按顺序记录一下我是怎么做的，以及踩过的坑。&lt;/p&gt;
&lt;h2&gt;Workers 是什么&lt;/h2&gt;
&lt;p&gt;可以把 Worker 理解成“一段放在 Cloudflare 机房里的 JavaScript 函数”。每次有人访问它的网址，Cloudflare 就在离访客最近的机房里运行这个函数，函数返回什么，访客就看到什么。&lt;/p&gt;
&lt;p&gt;最小的 Worker 长这样：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export default {
  async fetch(request, env, ctx) {
    return new Response(&quot;Hello, Dreamer!&quot;);
  },
};
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;request&lt;/code&gt;：这次请求的信息（网址、方法、请求头、请求体）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;env&lt;/code&gt;：绑定（Bindings），比如数据库、AI，后面会讲&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ctx&lt;/code&gt;：可以用 &lt;code&gt;ctx.waitUntil()&lt;/code&gt; 让一些任务在返回响应之后继续在后台跑完&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;不用买服务器，免费版每天有 10 万次请求，学习完全够用。&lt;/p&gt;
&lt;h2&gt;工具一：短链接（Workers + KV）&lt;/h2&gt;
&lt;h3&gt;思路&lt;/h3&gt;
&lt;p&gt;短链接的本质就是一张“对照表”：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;短码&lt;/th&gt;
&lt;th&gt;原网址&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;AcsDNY&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://blog.dogelover.online/posts/...&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;这张表我存在 &lt;strong&gt;Workers KV&lt;/strong&gt; 里。KV 是 Cloudflare 的“键值存储”，就像一个超大的字典：用键（key）存，用键取。这里键是 6 位短码，值是一段 JSON：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{&quot;url&quot;:&quot;https://...&quot;,&quot;clicks&quot;:3,&quot;created&quot;:&quot;2026-10-08T12:00:00.000Z&quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Worker 只需要处理几种请求：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;POST /api/shorten&lt;/code&gt;：收到一个长网址，生成短码，存进 KV&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /xxxxxx&lt;/code&gt;：按短码查 KV，找到就跳转过去&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /api/stats/xxxxxx&lt;/code&gt;：查看点击次数&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;生成短链接&lt;/h3&gt;
&lt;p&gt;核心就是一句 &lt;code&gt;env.LINKS.put()&lt;/code&gt;。&lt;code&gt;LINKS&lt;/code&gt; 是我给 KV 绑定起的名字，KV 只能存字符串，所以要先 &lt;code&gt;JSON.stringify&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// POST /api/shorten（节选）
const check = validateUrl(body &amp;amp;&amp;amp; body.url, selfUrl); // 只接受正常的 http/https 网址
if (!check.ok) return jsonResponse({ error: check.error }, 400);

const code = await createUniqueCode(env); // 生成一个没被占用的 6 位短码
const record = { url: check.url, clicks: 0, created: new Date().toISOString() };
await env.LINKS.put(code, JSON.stringify(record));

return jsonResponse({ short: `${selfUrl.origin}/${code}`, code, url: check.url }, 201);
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;跳转 + 点击计数&lt;/h3&gt;
&lt;p&gt;访问短链接时，查到记录就返回 &lt;strong&gt;302 跳转&lt;/strong&gt;。这里有两个我觉得挺有意思的小细节：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const record = await env.LINKS.get(code, { type: &quot;json&quot; });
if (!record || !record.url) return htmlResponse(notFoundPage(code), 404);

// 点击数 +1：放进 waitUntil，先让用户跳走，写 KV 在后台慢慢做
const updated = { ...record, clicks: (record.clicks || 0) + 1 };
ctx.waitUntil(
  env.LINKS.put(code, JSON.stringify(updated)).catch((err) =&amp;gt;
    console.warn(&quot;点击计数写入失败：&quot;, err)
  )
);

return new Response(null, {
  status: 302,
  headers: { Location: record.url, &quot;Cache-Control&quot;: &quot;no-store&quot; },
});
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;为什么用 302 而不是 301？&lt;/strong&gt; 301 是“永久跳转”，浏览器会把它缓存起来，下次直接跳，不再经过 Worker，点击就数不到了。302 是“临时跳转”，每次都会来问一遍。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;为什么用 &lt;code&gt;ctx.waitUntil&lt;/code&gt;？&lt;/strong&gt; 写 KV 需要一点时间，没必要让访客干等。先把跳转发出去，计数在后台写完就行。&lt;code&gt;.catch&lt;/code&gt; 保证就算写入失败，跳转也不受影响。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;免费额度要注意&lt;/h3&gt;
&lt;p&gt;KV 免费版每天读取 10 万次，但&lt;strong&gt;写入只有 1,000 次&lt;/strong&gt;。我这里“生成一个短链接”是一次写入，“每被点击一次”也是一次写入。自己用完全够，但如果哪天某个短链接被疯狂转发，计数可能当天就写不进去了（跳转本身不受影响，因为只用到读取）。&lt;/p&gt;
&lt;h2&gt;工具二：AI 小助手（Workers AI）&lt;/h2&gt;
&lt;h3&gt;绑定 AI&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Workers AI&lt;/strong&gt; 让 Worker 可以直接调用 Cloudflare 机房里的大模型，不需要自己申请什么 API Key。只要在 Worker 的设置里加一个 AI 绑定，起名叫 &lt;code&gt;AI&lt;/code&gt;，代码里就能用 &lt;code&gt;env.AI.run(模型ID, 参数)&lt;/code&gt; 调用模型。&lt;/p&gt;
&lt;p&gt;我用的主模型是 &lt;code&gt;@cf/zai-org/glm-4.7-flash&lt;/code&gt;，备用模型是 &lt;code&gt;@cf/qwen/qwen3-30b-a3b-fp8&lt;/code&gt;：主模型出错时自动换备用的再试一次。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const CONFIG = {
  MODEL: &quot;@cf/zai-org/glm-4.7-flash&quot;,
  FALLBACK_MODEL: &quot;@cf/qwen/qwen3-30b-a3b-fp8&quot;,
};

async function runAI(env, ctx, messages, { temperature, stream, meta }) {
  const models = [CONFIG.MODEL, CONFIG.FALLBACK_MODEL];
  let lastError = null;
  for (const model of models) {
    try {
      const result = await env.AI.run(model, { messages, stream, temperature });
      if (!stream) return jsonResponse({ ok: true, model, text: extractText(result) });
      return sseResponse(convertStream(result, { model, ...meta }), ctx);
    } catch (err) {
      lastError = err;
      if (isQuotaError(err)) break; // 额度用完了，换模型也没用
    }
  }
  return jsonError(429, &quot;今天的免费额度用完了，明天再来吧。&quot;);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;messages&lt;/code&gt; 就是和 ChatGPT 类似的对话格式：一条 &lt;code&gt;system&lt;/code&gt; 告诉 AI “你是谁、要怎么做”，后面是 &lt;code&gt;user&lt;/code&gt; 和 &lt;code&gt;assistant&lt;/code&gt; 轮流说话。翻译和问答其实是同一个模型，只是 &lt;code&gt;system&lt;/code&gt; 提示词不一样。翻译方向（中→英还是英→中）我用代码先判断好，再写进提示词，比让 AI 自己猜稳定得多。&lt;/p&gt;
&lt;h3&gt;流式输出（SSE）&lt;/h3&gt;
&lt;p&gt;如果等 AI 把整段话写完再返回，用户要盯着空白页面等好几秒。所以我开了 &lt;code&gt;stream: true&lt;/code&gt;，让模型“边想边吐字”，Worker 再用 &lt;strong&gt;SSE（Server-Sent Events）&lt;/strong&gt; 一点一点推给网页：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;return new Response(readable, {
  headers: {
    &quot;content-type&quot;: &quot;text/event-stream; charset=utf-8&quot;,
    &quot;cache-control&quot;: &quot;no-cache&quot;,
  },
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;网页收到的是一行一行的 &lt;code&gt;data: {...}&lt;/code&gt;，每行带几个新字，拼起来就是打字机效果。&lt;/p&gt;
&lt;h3&gt;免费额度：Neurons&lt;/h3&gt;
&lt;p&gt;Workers AI 按 &lt;strong&gt;Neurons&lt;/strong&gt; 计量，免费版&lt;strong&gt;每天 10,000 Neurons&lt;/strong&gt;，北京时间每天早上 8 点（UTC 0 点）重置。我做的这种短翻译和短问答，一次只消耗一点点。&lt;/p&gt;
&lt;p&gt;让我比较放心的一点是：&lt;strong&gt;免费版额度用完后只会报错，不会扣钱&lt;/strong&gt;。我在代码里把这个错误识别出来，换成了一句中文提示“今天的免费额度用完了”，而不是甩给用户一堆英文报错。&lt;/p&gt;
&lt;h2&gt;把两个工具放进博客：CORS&lt;/h2&gt;
&lt;p&gt;一开始两个工具各有各的网页，分别在 &lt;code&gt;dreamer-link.….workers.dev&lt;/code&gt; 和 &lt;code&gt;dreamer-ai.….workers.dev&lt;/code&gt;。我想把它们都放进博客的 &lt;a href=&quot;https://blog.dogelover.online/tools/&quot;&gt;工具页&lt;/a&gt;，网页用博客的样式，背后还是调用这两个 Worker。&lt;/p&gt;
&lt;p&gt;结果第一次预览，工具页只显示“暂时连不上”。原因就是 &lt;strong&gt;跨域（CORS）&lt;/strong&gt;。&lt;/p&gt;
&lt;h3&gt;为什么会被拦&lt;/h3&gt;
&lt;p&gt;博客在 &lt;code&gt;blog.dogelover.online&lt;/code&gt;（以及原来的 &lt;code&gt;dreamer-home.pages.dev&lt;/code&gt;），Worker 在 &lt;code&gt;workers.dev&lt;/code&gt;，对浏览器来说这是&lt;strong&gt;两个不同的网站&lt;/strong&gt;。出于安全考虑，浏览器默认不让一个网站的页面去读另一个网站接口返回的内容，除非对方明确说“我允许你”。&lt;/p&gt;
&lt;p&gt;而且像我这种发 JSON 的 &lt;code&gt;POST&lt;/code&gt; 请求，浏览器会先偷偷发一个 &lt;strong&gt;OPTIONS 预检请求&lt;/strong&gt;，问 Worker：“&lt;code&gt;blog.dogelover.online&lt;/code&gt; 想用 POST 调你，行不行？” Worker 回答“行”，真正的请求才会发出去。&lt;/p&gt;
&lt;h3&gt;我的做法：白名单&lt;/h3&gt;
&lt;p&gt;我在两个 Worker 里都加了一份允许名单，只放行我的博客、博客的预览地址和本机调试地址：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CORS_ORIGINS: [&quot;https://blog.dogelover.online&quot;, &quot;https://dreamer-home.pages.dev&quot;],

function isAllowedOrigin(origin) {
  if (!origin) return false;
  if (CONFIG.CORS_ORIGINS.includes(origin)) return true;
  // 博客的 Pages 预览地址，例如 https://3f2a1b4c.dreamer-home.pages.dev
  if (/^https:\/\/[a-z0-9-]+\.dreamer-home\.pages\.dev$/.test(origin)) return true;
  // 本机调试：http://localhost:4321 之类
  if (/^http:\/\/(localhost|127\.0\.0\.1)(:\d{1,5})?$/.test(origin)) return true;
  return false;
}

function corsHeaders(request) {
  const origin = request.headers.get(&quot;origin&quot;);
  const headers = { Vary: &quot;Origin&quot; };
  if (isAllowedOrigin(origin)) {
    headers[&quot;Access-Control-Allow-Origin&quot;] = origin;
    headers[&quot;Access-Control-Allow-Methods&quot;] = &quot;GET, POST, OPTIONS&quot;;
    headers[&quot;Access-Control-Allow-Headers&quot;] = &quot;Content-Type&quot;;
    headers[&quot;Access-Control-Max-Age&quot;] = &quot;86400&quot;; // 预检结果缓存 1 天
  }
  return headers;
}

// 在 fetch 入口最前面：预检请求直接回 204
if (request.method === &quot;OPTIONS&quot;) return preflightResponse(request);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里我没有偷懒写 &lt;code&gt;Access-Control-Allow-Origin: *&lt;/code&gt;（允许所有网站）。如果写了 &lt;code&gt;*&lt;/code&gt;，别人把我的工具页照抄一份放到他自己的网站上，就能白嫖我的 AI 额度。用白名单的话，别的网站在浏览器里就调不动了。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;小提醒：CORS 只是&lt;strong&gt;浏览器&lt;/strong&gt;的规矩。如果有人直接用 curl 之类的工具调接口，CORS 拦不住，所以 Worker 里该做的输入检查（网址格式、长度限制）还是要做。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;另外，发布顺序也有讲究：&lt;strong&gt;先更新 Worker（加上白名单），再更新博客&lt;/strong&gt;。反过来的话，新工具页上线的那几分钟里会一直显示“连不上”。&lt;/p&gt;
&lt;h2&gt;踩过的坑&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;在控制台粘贴代码出现乱码。&lt;/strong&gt; 我是在 Cloudflare 控制台的在线编辑器里直接粘代码的。有一次代码里的中文注释粘进去变成了一堆乱码（mojibake），部署后网页上的中文也全乱了。后来换成从一个 UTF-8 编码的网页里复制代码，就正常了。教训：&lt;strong&gt;粘贴完先扫一眼中文&lt;/strong&gt;，再点部署。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;绑定要在 Settings 里加。&lt;/strong&gt; 代码里写了 &lt;code&gt;env.LINKS&lt;/code&gt;、&lt;code&gt;env.AI&lt;/code&gt;，不代表它们就存在。必须到 Worker 的 &lt;strong&gt;Settings → Bindings&lt;/strong&gt; 里手动添加 KV 命名空间和 Workers AI，并且&lt;strong&gt;名字要和代码里一模一样&lt;/strong&gt;（大小写也算）。没绑定时 &lt;code&gt;env.LINKS&lt;/code&gt; 是 &lt;code&gt;undefined&lt;/code&gt;，会直接报错。我在 AI 小助手里加了一个 &lt;code&gt;/api/health&lt;/code&gt; 接口，能直接看到“AI 绑定：已绑定 / 未绑定”，排查起来方便很多。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AI 不太听话。&lt;/strong&gt; 我让它“用一句话介绍”，它有时还是会写两段，还带了个外卖和便利店的比喻 😂。提示词写得越具体，效果越好，这个还得慢慢调。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;小结&lt;/h2&gt;
&lt;p&gt;这次学到的东西：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Workers&lt;/strong&gt;：一段跑在 Cloudflare 机房里的函数&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;KV&lt;/strong&gt;：简单的键值存储，读多写少的场景很合适，注意每天 1,000 次写入&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Workers AI&lt;/strong&gt;：通过绑定调用大模型，&lt;code&gt;env.AI.run()&lt;/code&gt; 一行搞定，免费每天 10,000 Neurons，超了只报错不扣钱&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SSE 流式输出&lt;/strong&gt;：让 AI 回答有打字机效果&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CORS&lt;/strong&gt;：跨网站调用接口要对方放行，用白名单比用 &lt;code&gt;*&lt;/code&gt; 安全&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;两个工具都在 &lt;a href=&quot;https://blog.dogelover.online/tools/&quot;&gt;工具页&lt;/a&gt;，欢迎来试试～&lt;/p&gt;
</content:encoded></item><item><title>关于这个博客</title><link>https://blog.dogelover.online/posts/about-this-blog/</link><guid isPermaLink="true">https://blog.dogelover.online/posts/about-this-blog/</guid><description>这个博客是怎么搭起来的，以及我打算在这里写些什么。</description><pubDate>Wed, 07 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;你好，我是 Dreamer，一名工科学生。这里是我的个人博客，主要记录学习笔记和折腾过程。&lt;/p&gt;
&lt;h2&gt;用了什么技术&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://astro.build/&quot;&gt;Astro&lt;/a&gt;&lt;/strong&gt;：一个适合做内容网站的前端框架，把 Markdown 文章编译成静态网页&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/saicaca/fuwari&quot;&gt;Fuwari&lt;/a&gt;&lt;/strong&gt;：基于 Astro 的开源博客模板（MIT 协议），自带深色模式、文章目录、全站搜索和归档&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://pages.cloudflare.com/&quot;&gt;Cloudflare Pages&lt;/a&gt;&lt;/strong&gt;：负责托管网站，自动配好 HTTPS 和全球 CDN，而且免费&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;写文章只需要在 &lt;code&gt;src/content/posts/&lt;/code&gt; 下新建一个 Markdown 文件，构建之后就会变成一个网页。&lt;/p&gt;
&lt;h2&gt;打算写什么&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Cloudflare 的学习笔记：Pages、Workers、D1、R2、Workers AI……&lt;/li&gt;
&lt;li&gt;做小项目的过程和踩过的坑&lt;/li&gt;
&lt;li&gt;专业课和其他感兴趣的东西（待补充）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;欢迎常来看看。&lt;/p&gt;
</content:encoded></item></channel></rss>