描述 WebSocket API

了解如何使用 Mock Service Worker 描述 WebSocket API。

导入

¥Import

MSW 提供了一个指定的 ws 命名空间来描述 WebSocket 事件。我们将使用该命名空间来描述要拦截哪些连接和事件以及如何处理它们。

¥MSW provides a designated ws namespace for describing WebSocket events. We will use that namespace to describe what connections and events to intercept and how to handle them.

Import the ws namespace from the msw package:

// src/mocks/handlers.js
import { ws } from 'msw'
 
export const handlers = []

事件处理程序

¥Event handler

WebSocket 通信是基于事件的,因此我们将使用事件处理程序来拦截和描述它们。

¥WebSocket communications are event-based so we will be using an event handler to intercept and describe them.

在本教程中,我们将描述一个使用 WebSocket 发送和接收消息的聊天应用。我们将使用 MSW 替代实际的 WebSocket 服务器,先进行模拟开发。

¥In this tutorial, we will describe a chat application that uses WebSocket to send and receive messages. We will use MSW as a substitute for an actual WebSocket server, developing mock-first.

你可以将聊天应用想象成这样:

¥You can imagine the chat application like this:

// src/app.js
const ws = new WebSocket('wss://chat.example.com')
 
// Handle receiving messages.
ws.addEventListener('message', (event) => {
  renderMessage(event.data)
})
 
// Handle sending messages.
const handleFormSubmit = (event) => {
  const data = new FormData(event.target)
  const message = data.get('message')
  ws.send(message)
}

让我们首先使用 ws.link() 方法为 WebSocket 端点创建一个事件处理程序。

¥Let’s start by creating an event handler for a WebSocket endpoint using the ws.link() method.

Call ws.link() to declare an event handler:

// src/mocks/handlers.js
import { ws } from 'msw'
 
// The "chat" object is an event handler responsible
// for intercepting and mocking any WebSocket events
// to the provided endpoint.
const chat = ws.link('wss://chat.example.com')
 
export const handlers = [
  chat.addEventListener('connection', ({ client }) => {
    console.log('Intercepted a WebSocket connection:', client.url)
  }),
]

ws.link() 方法返回的 chat 对象为我们提供了类似服务器的 API,以便与拦截的 WebSocket 连接进行交互。我们可以添加 "connection" 事件监听器,以便了解应用中的客户端何时尝试连接到指定的 WebSocket 服务器。

¥The chat object returned from the ws.link() method gives us the server-like API to interact with the intercepted WebSocket connection. We can add the "connection" event listener to know when a client in our application tries to connect to the specified WebSocket server.

接下来,让我们描述如何处理客户端发送的聊天消息并模拟对它们的响应的服务器。

¥Next, let’s describe how to handle the chat messages that the client sends and mock the server responding to them.

响应客户端消息

¥Responding to client messages

每当 WebSocket 客户端向服务器发送数据时,"connection" 事件监听器参数中的 client 对象将发出 "message" 事件。我们可以将监听器附加到该事件,以监听并响应传出的客户端消息。

¥Whenever the WebSocket client sends data to the server, the client object in the "connection" event listener argument will emit the "message" event. We can attach a listener to that event to listen and react to outgoing client messages.

client 添加 "message" 监听器以拦截客户端事件:

¥Add a "message" listener to the client to intercept client events:

// src/mocks/handlers.js
import { ws } from 'msw'
 
const chat = ws.link('wss://chat.example.com')
 
export const handlers = [
  chat.addEventListener('connection', ({ client }) => {
    client.addEventListener('message', (event) => {
      console.log('client sent:', event.data)
    })
  }),
]

现在我们知道客户端何时在聊天中发送消息,我们可以从 “server”(即我们的事件处理程序)发回数据。

¥Now that we know when the client sends a message in the chat, we can send data back from the “server”, which is our event handler.

要将数据从服务器发送到客户端,我们可以使用 client 对象提供的 client.send() 方法。

¥To send data from the server to the client, we can use the client.send() method provided by the client object.

Call client.send() to send data to the client:

// src/mocks/handlers.js
import { ws } from 'msw'
 
const chat = ws.link('wss://chat.example.com')
 
export const handlers = [
  chat.addEventListener('connection', ({ client }) => {
    client.addEventListener('message', (event) => {
      client.send('hello from server!')
    })
  }),
]

现在,每当客户端发送消息时,我们的 chat 事件处理程序都会拦截它并返回 "hello from server!" 字符串。你可以将此交互视为响应你从应用发送的任何消息而到达的模拟聊天消息。

¥Now, whenever the client sends a message, our chat event handler intercepts it and sends back a "hello from server!" string. You can think of this interaction as a mock chat message arriving in response to any message you send from the application.

到目前为止,我们的事件处理程序一直在与单个 client 交互。让我们看看如何在所有客户端之间广播数据以实现实时聊天功能。

¥Our event handler has been interacting with a single client so far. Let’s take a look how to broadcast data across all clients to implement the realtime chat functionality.

广播数据

¥Broadcasting data

当单个客户端发送消息时,我们希望将该消息广播给所有连接的客户端,以便他们能够在应用中看到它。为此,我们的 chat 事件处理程序对象提供了我们可以使用的 broadcast() 方法。

¥When a single client sends a message, we want to broadcast that message to all connected clients so they would see it in their applications. To do so, our chat event handler object provides a broadcast() method that we can use.

调用 chat.broadcast() 将消息广播给所有客户端:

¥Call chat.broadcast() to broadcast the message to all clients:

// src/mocks/handlers.js
import { ws } from 'msw'
 
const chat = ws.link('wss://chat.example.com')
 
export const handlers = [
  chat.addEventListener('connection', ({ client }) => {
    client.addEventListener('message', (event) => {
      chat.broadcast(event.data)
    })
  }),
]

使用事件处理程序的 .broadcast() 方法时,所有连接的客户端都将收到发送的数据。这包括发送我们正在广播的消息的 client!根据你实现聊天的方式,你可能希望从此广播中省略初始客户端(例如,如果你乐观地显示客户端的已发送消息)。

¥When using the .broadcast() method of the event handler, all the connected clients will receive the sent data. That includes the client that has sent the message we are broadcasting! Depending on how you implement your chat, you may want to omit the initial client from this broadcasting (e.g. if you display the sent message for the client optimistically).

要将数据广播到除客户端子集之外的所有客户端,请在事件处理程序对象上使用 .broacastExcept() 方法。

¥To broadcast data to all clients except a subset of clients, use the .broacastExcept() method on the event handler object.

调用 chat.broadcastExcept() 将消息广播给除初始发送者之外的所有客户端:

¥Call chat.broadcastExcept() to broadcast the message to all clients except the initial sender:

// src/mocks/handlers.js
import { ws } from 'msw'
 
const chat = ws.link('wss://chat.example.com')
 
export const handlers = [
  chat.addEventListener('connection', ({ client }) => {
    client.addEventListener('message', (event) => {
      chat.broadcastExcept(client, event.data)
    })
  }),
]

现在,每当客户端向聊天发送消息时,该消息都会广播给所有其他客户端,以便他们也能在 UI 中看到它。

¥Now, whenever a client sends a message to the chat, it will be broadcasted to all the other clients so they would see it in the UI too.

后续步骤

¥Next steps

集成

¥Integrations

一旦你描述了所需的网络行为,请将其集成到应用中的任何环境中。

¥Once you have described the network behavior you want, integrate it into any environment in your application.

请注意,某些环境(如 Node.js)尚未提供全局 WebSocket API。在这些情况下,你可能需要配置你的环境以填充 WebSocket 类。

¥Note that some envirionments, like Node.js, do not ship the global WebSocket API yet. You may want to configure your environment to polyfill the WebSocket class in those cases.

了解如何处理 WebSocket 事件

¥Learn about handling WebSocket events

本教程包含描述聊天应用的 WebSocket 通信的最小功能。你可以在 MSW 中使用 WebSosckets 做更多事情,例如连接到实际服务器、修改服务器发送的事件、模拟错误和连接关闭。

¥This tutorial includes a minimal functionality to describe the WebSocket communication for a chat application. There’s much more you can do with WebSosckets in MSW, like connecting to the actual server, modifying server-sent events, mocking errors and connection closures.

在此页面上了解有关你可以使用 WebSocket 连接执行的操作的更多信息:

¥Learn more about what you can do with WebSocket connections on this page:

Handling WebSocket events

Learn how to intercept and mock WebSocket events.