跳转到内容
搜索文档

使用 WebSockets API

使用 WebSockets API 与 Cloudflare Workers 进行实时通信。

最后更新 查看 MarkdownAgent 设置

WebSockets 允许你与 Cloudflare Workers 无服务器函数进行实时通信。本指南介绍 Cloudflare Workers 上 WebSockets 的基础知识,包括如何在 Workers 函数中编写 WebSocket 服务器,以及如何作为客户端连接并使用这些 WebSocket 服务器。

WebSockets 是客户端与源服务器之间保持的开放连接。在 WebSocket 连接内,客户端与源服务器可以来回传递数据,而无需重新建立会话。这使得在 WebSocket 连接中交换数据非常快速。WebSockets 常用于实时应用,如在线聊天和游戏。

编写 WebSocket 服务器

Cloudflare Workers 中的 WebSocket 服务器允许你实时接收来自客户端的消息。本指南展示如何在 Workers 中设置 WebSocket 服务器。

客户端可以在浏览器中通过实例化新的 WebSocket,并传入 Workers 函数的 URL 来发起 WebSocket 请求:

// In client-side JavaScript, connect to your Workers function using WebSockets:
const websocket = new WebSocket(
	"wss://example-websocket.signalnerve.workers.dev",
);

当传入的 WebSocket 请求到达 Workers 函数时,会包含 Upgrade 标头,值为字符串 websocket。在继续实例化 WebSocket 之前,请检查此标头:

async function handleRequest(request) {
  const upgradeHeader = request.headers.get('Upgrade');
  if (!upgradeHeader || upgradeHeader !== 'websocket') {
    return new Response('Expected Upgrade: websocket', { status: 426 });
  }
}
use worker::*;

#[event(fetch)]
async fn fetch(req: HttpRequest, _env: Env, _ctx: Context) -> Result<worker::Response> {
    let upgrade_header = match req.headers().get("Upgrade") {
        Some(h) => h.to_str().unwrap(),
        None => "",
    };
    if upgrade_header != "websocket" {
        return worker::Response::error("Expected Upgrade: websocket", 426);
    }
}

检查 Upgrade 标头后,可以创建新的 WebSocketPair 实例,其中包含服务器端和客户端 WebSocket。其中一个 WebSocket 由 Workers 函数处理,另一个作为 101 状态码Response 的一部分返回,表示请求正在切换协议:

async function handleRequest(request) {
  const upgradeHeader = request.headers.get('Upgrade');
  if (!upgradeHeader || upgradeHeader !== 'websocket') {
    return new Response('Expected Upgrade: websocket', { status: 426 });
  }

  const webSocketPair = new WebSocketPair();
  const client = webSocketPair[0],
    server = webSocketPair[1];

  return new Response(null, {
    status: 101,
    webSocket: client,
  });
}
use worker::*;

#[event(fetch)]
async fn fetch(req: HttpRequest, _env: Env, _ctx: Context) -> Result<worker::Response> {
    let upgrade_header = match req.headers().get("Upgrade") {
        Some(h) => h.to_str().unwrap(),
        None => "",
    };
    if upgrade_header != "websocket" {
        return worker::Response::error("Expected Upgrade: websocket", 426);
    }

    let ws = WebSocketPair::new()?;
    let client = ws.client;
    let server = ws.server;
    server.accept()?;

    worker::Response::from_websocket(client)

}

WebSocketPair 构造函数返回一个对象,01 键各持有一个 WebSocket 实例。常见做法是使用 Object.valuesES6 解构 从该对中获取两个 WebSocket,如下例所示。

要在 Worker 中与 client WebSocket 开始通信,请在 server WebSocket 上调用 accept。这会告诉 Workers 运行时监听 WebSocket 数据,并与 client WebSocket 保持连接:

async function handleRequest(request) {
  const upgradeHeader = request.headers.get('Upgrade');
  if (!upgradeHeader || upgradeHeader !== 'websocket') {
    return new Response('Expected Upgrade: websocket', { status: 426 });
  }

  const webSocketPair = new WebSocketPair();
  const [client, server] = Object.values(webSocketPair);

  server.accept();

  return new Response(null, {
    status: 101,
    webSocket: client,
  });
}
use worker::*;

#[event(fetch)]
async fn fetch(req: HttpRequest, _env: Env, _ctx: Context) -> Result<worker::Response> {
    let upgrade_header = match req.headers().get("Upgrade") {
        Some(h) => h.to_str().unwrap(),
        None => "",
    };
    if upgrade_header != "websocket" {
        return worker::Response::error("Expected Upgrade: websocket", 426);
    }

    let ws = WebSocketPair::new()?;
    let client = ws.client;
    let server = ws.server;
    server.accept()?;

    worker::Response::from_websocket(client)

}

WebSockets 会发出多个可通过 addEventListener 连接的事件。以下示例监听 message 事件,并用其中的数据输出 console.log

async function handleRequest(request) {
  const upgradeHeader = request.headers.get('Upgrade');
  if (!upgradeHeader || upgradeHeader !== 'websocket') {
    return new Response('Expected Upgrade: websocket', { status: 426 });
  }

  const webSocketPair = new WebSocketPair();
  const [client, server] = Object.values(webSocketPair);

  server.accept();
  server.addEventListener('message', event => {
    console.log(event.data);
  });

  return new Response(null, {
    status: 101,
    webSocket: client,
  });
}
use futures::StreamExt;
use worker::*;

#[event(fetch)]
async fn fetch(req: HttpRequest, _env: Env, _ctx: Context) -> Result<worker::Response> {
    let upgrade_header = match req.headers().get("Upgrade") {
        Some(h) => h.to_str().unwrap(),
        None => "",
    };
    if upgrade_header != "websocket" {
        return worker::Response::error("Expected Upgrade: websocket", 426);
    }

    let ws = WebSocketPair::new()?;
    let client = ws.client;
    let server = ws.server;
    server.accept()?;

    wasm_bindgen_futures::spawn_local(async move {
        let mut event_stream = server.events().expect("could not open stream");
        while let Some(event) = event_stream.next().await {
            match event.expect("received error in websocket") {
                WebsocketEvent::Message(msg) => server.send(&msg.text()).unwrap(),
                WebsocketEvent::Close(event) => console_log!("{:?}", event),
            }
        }
    });
    worker::Response::from_websocket(client)

}
import { Hono } from 'hono'
import { upgradeWebSocket } from 'hono/cloudflare-workers'

const app = new Hono()

app.get(
  '*',
  upgradeWebSocket((c) => {
    return {
      onMessage(event, ws) {
        console.log('Received message from client:', event.data)
        ws.send(`Echo: ${event.data}`)
      },
      onClose: () => {
        console.log('WebSocket closed:', event)
      },
      onError: () => {
        console.error('WebSocket error:', event)
      },
    }
  })
)

export default app;

从客户端连接到 WebSocket 服务器

编写与 Workers 函数通信的 WebSocket 客户端分两步:首先创建 WebSocket 实例,然后为其附加事件监听器:

const websocket = new WebSocket(
	"wss://websocket-example.signalnerve.workers.dev",
);
websocket.addEventListener("message", (event) => {
	console.log("Message received from server");
	console.log(event.data);
});

WebSocket 客户端可以使用 send 函数向服务器发送消息:

websocket.send("MESSAGE");

WebSocket 交互完成后,客户端可以使用 close 关闭连接:

websocket.close();

有关实际示例,请参阅 websocket-template 以开始使用 WebSockets。

编写 WebSocket 客户端

Cloudflare Workers 支持 new WebSocket(url) 构造函数。Worker 可以像上述客户端实现一样,以相同方式建立到远程服务器的 WebSocket 连接。

此外,Cloudflare 支持通过发起 fetch 请求并设置 Upgrade 标头来建立 WebSocket 连接。

async function websocket(url) {
	// Make a fetch request including `Upgrade: websocket` header.
	// The Workers Runtime will automatically handle other requirements
	// of the WebSocket protocol, like the Sec-WebSocket-Key header.
	let resp = await fetch(url, {
		headers: {
			Upgrade: "websocket",
		},
	});

	// If the WebSocket handshake completed successfully, then the
	// response has a `webSocket` property.
	let ws = resp.webSocket;
	if (!ws) {
		throw new Error("server didn't accept WebSocket");
	}

	// Call accept() to indicate that you'll be handling the socket here
	// in JavaScript, as opposed to returning it on to a client.
	// You can pass { allowHalfOpen: true } if you need to coordinate
	// the close handshake manually (for example, when proxying).
	ws.accept();

	// Now you can send and receive messages like before.
	ws.send("hello");
	ws.addEventListener("message", (msg) => {
		console.log(msg.data);
	});
}

WebSocket 关闭行为

启用 web_socket_auto_reply_to_close 兼容标志(在 2026-04-07 及之后的兼容日期上默认启用)后,Workers 运行时会自动回复传入的 Close 帧,并在触发 close 事件前将 readyState 切换为 CLOSED。你无需在 close 事件处理程序中调用 close(),但这样做是安全的(调用会被静默忽略)。

如需半开连接行为(例如 WebSocket 代理),向 accept() 传入 { allowHalfOpen: true }。请注意,此标志生效后 new WebSocket(url) 始终自动回复。要对客户端 WebSocket 获得半开行为,请使用上述基于 fetch() 的模式,并调用 ws.accept({ allowHalfOpen: true })

更多详情,请参阅 WebSocket 关闭行为

WebSocket 压缩

Cloudflare Workers 支持 WebSocket 压缩。更多信息请参阅 WebSocket 压缩

这篇文档对您有帮助吗?