IcyBlog

把博客在线人数迁到 Cloudflare Durable Object

cloudflare 站务 技术
771 4 分钟

前言

博客页脚之前有一个“正在被 X 人看爆”的实时在线人数功能,做法很简单:浏览器连一个 WebSocket 后端,后端统计当前连接数,再把人数广播出去

这个方案本身没啥问题,甚至还挺准。问题是它需要一个长期在线的后端。

为了页脚一个小数字单独跑一坨东西,总感觉有点怪。尤其是博客主体已经是静态站了,再留一个常驻后端在旁边跑着,就很不serverless。

于是这次试着把这个功能迁到了 Cloudflare Workers + Durable Object。

_2026-06-27_11.55.11

什么是 Durable Object

按照 Cloudflare 文档 的说法,Durable Object 是一种特殊的 Cloudflare Worker,它把计算和存储放在一起。每个 Durable Object 都有全局唯一的名字,所以无论请求从哪里来,都可以被路由到同一个对象上。

NOTE

Cloudflare 文档里对它的描述是:A Durable Object is a special kind of Cloudflare Worker which uniquely combines compute with storage. 简单说就是,一个能记住状态的 Worker。

对我这个在线人数功能来说,最有用的不是它能存多少数据,而是它可以作为多个客户端之间的协调点。所有 WebSocket 连接都进同一个对象里,谁连上、谁断开,都在一个地方处理。

WARNING

Durable Object 适合这种需要协调状态的小功能,但不要把它想成万能后端。这里就拿它记录当前连接数,不额外搞复杂逻辑。

为什么换成 Durable Object

普通 Worker 是无状态的,适合做反代、简单鉴权等事情,

但是实时在线人数功能不同,他需要一个能记住连接状态的地方。Durable Object 刚好可以当这个小房间,所有 WebSocket 连接都丢进去,里面维护一个连接集合,集合长度就是当前在线人数。

大概流程如下:

浏览器 -> Worker /ws -> Durable Object -> 广播在线人数

完全不需要服务器,比较优雅

Worker 代码思路

核心逻辑其实很短。

Worker 暴露两个接口:

/ws     WebSocket 连接入口
/count  返回当前在线人数

Durable Object 里维护一个 Set<WebSocket>

private sessions = new Set<WebSocket>();

有新连接进来时加入集合,然后广播一次人数:

socket.accept();
this.sessions.add(socket);
this.broadcastCount();

连接关闭或者出错时,从集合里删掉,再广播一次:

private closeSession(socket: WebSocket) {
  if (!this.sessions.delete(socket)) return;
  this.broadcastCount();
}

广播的数据也比较简单:

{ "online": 1 }

属于是能用就行的级别。

Wrangler 配置

项目里新增了一个Worker目录 例如online-counter

wrangler.jsonc 里主要是 Durable Object 绑定:

{
  "name": "online-counter",
  "main": "src/index.ts",
  "compatibility_date": "2026-06-01",
  "durable_objects": {
    "bindings": [
      {
        "name": "ONLINE_COUNTER",
        "class_name": "OnlineCounterRoom"
      }
    ]
  },
  "migrations": [
    {
      "tag": "v1",
      "new_sqlite_classes": ["OnlineCounterRoom"]
    }
  ]
}

另外加了一个 ALLOWED_ORIGINS,只允许自己的博客域名连接,避免被奇怪的网站拿去蹭:

"vars": {
  "ALLOWED_ORIGINS": "https://blog.icybit.cn"
}

部署

先安装依赖:

bun install

登录 Cloudflare:

bunx wrangler login
_2026-06-27_11.59.25

然后部署:

bun run online:deploy

部署完之后,在 Cloudflare Dashboard 里给 Worker 绑定一个自定义域名就行

评论

Markdown

评论区加载中…