编写 WebSocket 客户端应用程序

注意:此功能在Web Workers中可用。

WebSocket 客户端应用程序使用WebSocket API通过 WebSocket 协议与WebSocket 服务器进行通信。

注意:本文中的示例代码片段取自我们的 WebSocket 聊天客户端/服务器示例。查看代码

创建 WebSocket 对象

为了使用 WebSocket 协议进行通信,您需要创建一个WebSocket对象;这将自动尝试打开与服务器的连接。

WebSocket 构造函数接受一个必需参数和一个可选参数

js
webSocket = new WebSocket(url, protocols);
url

要连接的 URL;这应该是 WebSocket 服务器将响应的 URL。这应该使用 URL 方案wss://,尽管某些软件可能允许您为本地连接使用不安全的ws://。相对 URL 值以及https://http://方案在大多数最新的浏览器版本中也允许。

protocols 可选

单个协议字符串或协议字符串数组。这些字符串用于指示子协议,以便单个服务器可以实现多个 WebSocket 子协议(例如,您可能希望一个服务器能够根据指定的protocol处理不同类型的交互)。如果您没有指定协议字符串,则假定为空字符串。

如果目标不允许访问,则构造函数将抛出SecurityError。如果您尝试使用不安全的连接,则可能会发生这种情况(大多数用户代理现在都要求所有 WebSocket 连接都使用安全链接,除非它们在同一设备上或可能在同一网络上)。

连接错误

如果在尝试连接时发生错误,则首先将error事件发送到WebSocket对象(从而调用任何处理程序),然后发送close事件,指示连接关闭的原因。

浏览器还可以将其控制台输出更具描述性的错误消息,以及RFC 6455,第 7.4 节中定义的关闭代码,通过CloseEvent

示例

此简单示例创建一个新的 WebSocket,连接到wss://www.example.com/socketserver处的服务器。在此示例中,在套接字请求中命名了一个自定义协议“protocolOne”,尽管可以省略。

js
const exampleSocket = new WebSocket(
  "wss://www.example.com/socketserver",
  "protocolOne",
);

返回后,exampleSocket.readyStateCONNECTING。一旦连接准备好传输数据,readyState将变为OPEN

如果您想打开连接并且对您支持的协议灵活,则可以指定协议数组

js
const exampleSocket = new WebSocket("wss://www.example.com/socketserver", [
  "protocolOne",
  "protocolTwo",
]);

一旦建立连接(即readyStateOPEN),exampleSocket.protocol将告诉您服务器选择了哪个协议。

建立 WebSocket 依赖于HTTP 升级机制,因此当我们将 Web 服务器地址为ws://www.example.comwss://www.example.com时,协议升级请求是隐式的。

向服务器发送数据

打开连接后,您可以开始向服务器传输数据。为此,请对要发送的每条消息调用WebSocket对象的send()方法

js
exampleSocket.send("Here's some text that the server is urgently awaiting!");

您可以将数据作为字符串、BlobArrayBuffer发送。

由于建立连接是异步的并且容易发生故障,因此无法保证在创建 WebSocket 对象后立即调用send()方法会成功。我们至少可以确定,尝试发送数据仅在建立连接后才发生,方法是定义一个onopen事件处理程序来执行此操作

js
exampleSocket.onopen = (event) => {
  exampleSocket.send("Here's some text that the server is urgently awaiting!");
};

使用 JSON 传输对象

您可以做的一件方便的事情是使用JSON向服务器发送相当复杂的数据。例如,聊天程序可以使用使用 JSON 封装数据包实现的协议与服务器交互

js
// Send text to all users through the server
function sendText() {
  // Construct a msg object containing the data the server needs to process the message from the chat client.
  const msg = {
    type: "message",
    text: document.getElementById("text").value,
    id: clientID,
    date: Date.now(),
  };

  // Send the msg object as a JSON-formatted string.
  exampleSocket.send(JSON.stringify(msg));

  // Blank the text input element, ready to receive the next line of text from the user.
  document.getElementById("text").value = "";
}

接收来自服务器的消息

WebSockets 是一个事件驱动的 API;当接收到消息时,message事件将发送到WebSocket对象。要处理它,请为message事件添加一个事件侦听器,或使用onmessage事件处理程序。要开始侦听传入数据,您可以执行以下操作

js
exampleSocket.onmessage = (event) => {
  console.log(event.data);
};

接收和解释 JSON 对象

让我们首先考虑使用 JSON 传输对象中提到的聊天客户端应用程序。客户端可能会接收各种类型的数据包,例如

  • 登录握手
  • 消息文本
  • 用户列表更新

解释这些传入消息的代码可能如下所示

js
exampleSocket.onmessage = (event) => {
  const f = document.getElementById("chatbox").contentDocument;
  let text = "";
  const msg = JSON.parse(event.data);
  const time = new Date(msg.date);
  const timeStr = time.toLocaleTimeString();

  switch (msg.type) {
    case "id":
      clientID = msg.id;
      setUsername();
      break;
    case "username":
      text = `User <em>${msg.name}</em> signed in at ${timeStr}<br>`;
      break;
    case "message":
      text = `(${timeStr}) ${msg.name} : ${msg.text} <br>`;
      break;
    case "rejectusername":
      text = `Your username has been set to <em>${msg.name}</em> because the name you chose is in use.<br>`;
      break;
    case "userlist":
      document.getElementById("userlistbox").innerText = msg.users.join("\n");
      break;
  }

  if (text.length) {
    f.write(text);
    document.getElementById("chatbox").contentWindow.scrollByPages(1);
  }
};

在这里,我们使用JSON.parse()将 JSON 对象转换回原始对象,然后检查并对其内容采取行动。

文本数据格式

通过 WebSocket 连接接收的文本采用 UTF-8 格式。

关闭连接

完成使用 WebSocket 连接后,请调用 WebSocket 方法close()

js
exampleSocket.close();

在尝试关闭连接之前检查套接字的bufferedAmount属性以确定网络上是否还有任何数据尚未传输可能会有所帮助。如果此值不为 0,则仍有待处理的数据,因此您可能希望等待后再关闭连接。

安全注意事项

WebSockets 不应在混合内容环境中使用;也就是说,您不应该从使用 HTTPS 加载的页面打开不安全的 WebSocket 连接,反之亦然。现在,大多数浏览器仅允许安全的 WebSocket 连接,并且不再支持在不安全的环境中使用它们。