六维教程

Cloudflare Workers WebSocket

最后一篇讲实时通信。WebSocket 是实现聊天、通知推送、在线协作的技术基础,也是 Workers 里公认的难点。它和 Durable Objects 是黄金搭档,学完这一篇,本教程的进阶部分就收官了。

什么是 WebSocket

普通 HTTP 请求是”一问一答”,浏览器发请求,服务器返回结果,连接就断开了。要实现实时消息,传统做法是轮询,浏览器每隔几秒反复问”有新消息吗”,浪费流量且不够及时。

WebSocket 建立一条全双工长连接,连接建立后,服务器和浏览器可以随时互相推送数据,不用反复建立连接

对比项 HTTP 轮询 WebSocket
连接方式 每轮询问都新建连接 一条连接长期保持
消息方向 只能浏览器先发 双向随时推送
实时性 取决于轮询间隔 毫秒级
典型场景 普通接口 聊天、推送、在线协作

为什么 Workers 需要 DO

WebSocket 连接是长连接,需要服务器侧持续保存”这个连接是谁”的状态。而普通 Worker 是无状态的,一个请求执行完资源就可能被回收,连接没人接管。

DO 实例可以长期存活并持有状态,正好承接 WebSocket 连接。连接的请求被转发给 DO 实例,之后这条连接的所有消息都由同一个实例处理,实例里还能存房间成员列表等状态。

握手流程

WebSocket 连接不是凭空建立的,要先通过 HTTP 完成”升级”握手

  1. 浏览器发送带 Upgrade 头的 HTTP 请求
  2. 服务器同意后返回 101 状态码
  3. 连接升级为 WebSocket 通道,双方开始双向通信

101 状态码就是 WebSocket 协议的标志,后面代码里会看到。

服务端实现

先定义一个聊天室的 DO 类,负责接收连接和广播消息

// src/index.js
export class ChatRoom {
  constructor(state, env) {
    this.state = state;
    this.connections = new Set();
  }

  // 处理握手请求
  async fetch(request) {
    // 生成一对客户端和服务端 WebSocket
    const pair = new WebSocketPair();
    const [client, server] = Object.values(pair);

    // 接管这条服务端连接
    this.state.acceptWebSocket(server);
    this.connections.add(server);

    server.send("欢迎加入聊天室");
    return new Response(null, { status: 101, webSocket: client });
  }

  // 收到客户端消息时触发
  async webSocketMessage(ws, message) {
    const text = String(message);
    // 广播给房间内其他连接
    for (const conn of this.connections) {
      if (conn !== ws) {
        conn.send(text);
      }
    }
  }

  // 连接关闭时触发
  async webSocketClose(ws, code, reason, wasClean) {
    this.connections.delete(ws);
  }
}

几个关键 API 要理解

API 作用
new WebSocketPair() 生成客户端/服务端两个成对的对象
state.acceptWebSocket(server) 接管连接,之后消息才能触发回调
ws.send(msg) 向这个连接推送消息
webSocketMessage 收到消息的回调,参数是消息内容
webSocketClose 连接关闭的回调,用来清理状态

再写 Worker 入口,把 /ws 路径的请求转发到聊天室 DO

export default {
  async fetch(request, env, ctx) {
    const url = new URL(request.url);

    if (url.pathname === "/ws") {
      // 按房间名获取稳定的 DO 实例
      const id = env.CHAT_ROOM.idFromName("room-1");
      const stub = env.CHAT_ROOM.get(id);
      return stub.fetch(request);
    }

    return new Response("请访问 /ws 建立 WebSocket 连接");
  },
};

最后在 wrangler.toml 注册 DO 类

name = "my-worker"
main = "src/index.js"
compatibility_date = "2026-01-01"

[durable_objects]
bindings = [{ name = "CHAT_ROOM", class_name = "ChatRoom" }]

[[migrations]]
tag = "v1"
new_sqlite_classes = ["ChatRoom"]

部署后访问 wss://my-worker.你的子域.workers.dev/ws(注意协议是 wss),不同浏览器打开多个标签页,任何一个发消息,其他标签页都能实时收到。

客户端实现

浏览器端的代码很短,原生 WebSocket API 即可

<script>
  const ws = new WebSocket("wss://my-worker.你的子域.workers.dev/ws");

  // 连接建立
  ws.onopen = () => {
    console.log("连接成功");
  };

  // 收到消息
  ws.onmessage = (event) => {
    console.log("收到消息", event.data);
  };

  // 发送消息
  function send(text) {
    ws.send(text);
  }

  // 连接关闭
  ws.onclose = () => {
    console.log("连接关闭");
  };
</script>

WebSocket 休眠(Hibernation)

每个 WebSocket 连接都会占用 DO 实例的内存。连接很多、消息很少时,让所有空闲连接一直占着内存不划算。平台提供了休眠机制,空闲连接被挂起时不占用实例资源,收到消息时自动唤醒并触发回调。

使用休眠机制后,webSocketMessage 等回调的写法不变,平台内部自动完成挂起和唤醒,对开发者透明。生产环境的高并发实时应用基本都会开启,新手了解存在即可,需要时查官方文档配置。

限制与计费

事项 说明
连接计费 每次握手算 1 次请求,之后的消息不再计费
单 Worker 连接数 约 1000 个,受计划限制
空闲超时 免费和 Pro 计划约 100 秒无消息会断开
消息大小 有限制,大消息建议分片

适用场景

场景 说明
实时聊天 聊天室、客服对话
消息推送 订单状态、通知提醒
在线协作 多人白板、协同编辑
实时数据 行情推送、游戏状态

到这里,本教程的 13 篇全部结束。回顾一下完整知识地图,入门概念、快速部署、本地开发、核心编程模型、路由与 API、环境变量、KV、D1、定时任务、调试部署、DO、WebSocket,已经覆盖了 Cloudflare Workers 最主要的知识点。剩下的进阶内容(R2、Queues、Workers AI、Hono 框架)建议在实战中按需学习,遇到问题再查官方文档。

上一篇 Cloudflare Workers Durable Objects

上一篇
Cloudflare Workers Durable Objects
下一篇
工作流编排基础