Mocking WebSocket

拦截和模拟 WebSocket 事件。

Mock Service Worker 提供对模拟 WebSocket API 的一流支持。你可以使用 msw 中的 ws 命名空间拦截 WebSocket 连接并模拟客户端和服务器事件:

¥Mock Service Worker comes with a first-class support for mocking WebSocket APIs. You can intercept WebSocket connections and mock client and server events using the ws namespace from msw:

import { ws } from 'msw'

ws

API reference for the `ws` namespace.

本页将概述使用 MSW 模拟 WebSocket 是什么样子的,并介绍上述模拟的重要默认值。

¥This page will give you a high-level overview of what mocking WebSockets with MSW looks like, as well as go through the important defaults of the said mocking.

标准优先

¥Standard-first

与 HTTP 和 GraphQL 类似,WebSocket 模拟旨在尊重和推广 Web 标准。拦截和模拟 WebSocket 通信的方式基于 WHATWG WebSocket 标准,这意味着将客户端视为 EventTarget,监听 messageclose 等事件,并从 MessageEvent 对象读取发送和接收的数据。

¥Much like HTTP and GraphQL, WebSocket mocking is designed to respect and promote web standards. The way you intercept and mock WebSocket communication is according to the WHATWG WebSocket Standard, which means treating clients as EventTarget, listening to events like message and close, and reading sent and received data from the MessageEvent objects.

我们没有计划支持自定义 WebSocket 协议,例如使用 HTTP 轮询的协议。这些函数是实现它们的第三方工具的专有函数,MSW 无法可靠地处理这些协议,除非使用非标准的、特定于供应商的逻辑。

¥We have no plans to support custom WebSocket protocols, such as those utilizing HTTP polling. Those are proprietary to the third-party tooling that implements them, and there is no reliable way for MSW to handle those protocols without shipping non-standard, vendor-specific logic.

话虽如此,我们承认标准 WebSocket 接口很少直接用于生产系统。我们提供了一系列 bindings 库,帮助你模拟基于 WebSocket 协议构建的客户端,例如 Socket.IO。

¥That being said, we acknowledge that the standard WebSocket interface is seldom used directly in production systems. We are providing a collection of bindings to help you mock clients built on top of the WebSocket protocol, like Socket.IO.

事件类型

¥Event types

WebSocket 通信是双工的,这意味着客户端和服务器都可以独立且同时地发送和接收事件。你可以使用该库处理两种类型的事件:

¥WebSocket communication is duplex, which means that both the client and the server can send and receive events independently and simultaneously. There are two types of events you can handle with the library:

  • 传出客户端事件(客户端到服务器)。这些事件由你的 WebSocket 客户端发送到原始服务器。你可以拦截此类事件,并决定是模拟服务器响应还是允许它们通过。

    ¥Outgoing client events (client-to-server). These are sent by your WebSocket client to the original server. You can intercept such events and decide whether to mock the server response or allow them to pass through.

  • 传入服务器事件(服务器到客户端)。这些事件是从你的原始服务器接收的。你也可以在这些事件到达客户端之前拦截它们,并决定是修改、阻止还是允许它们通过。

    ¥Incoming server events (server-to-client). These are received from your original server. You can intercept these events, too, before they reach the client and decide whether to modify them, prevent them, or let them pass through.

拦截连接

¥Intercepting connections

你可以在应用中拦截 WebSocket 连接,并使用该库作为客户端和原始服务器之间的中间件层:

¥You can intercept WebSocket connections in your app and use the library to act as a middleware layer that sits between your client and the original server:

client ⇄ MSW ⇄ server

首先导入 ws 命名空间并创建一个新的链接:

¥Start by importing the ws namespace and creating a new link:

import { ws } from 'msw'
 
const chat = ws.link('wss://chat.example.com')

你可以对 WebSocket 连接使用与 http 处理程序相同的 URL 谓词,其中包括绝对 URL 和相对 URL,以及路径参数、通配符和正则表达式。

¥You can use the same URL predicate for WebSocket connections as you use for the http handlers, which includes absolute and relative URLs as well as path parameters, wildcards, and regular expressions.

链接预先配置拦截器以匹配与提供的谓词(例如 URL)匹配的 WebSocket 连接。

¥A link preconfigures the interceptor to match WebSocket connections that match the provided predicate (e.g. URL).

在链接上添加 connectin 事件监听器,以拦截传出的客户端连接:

¥Add a connectin event listener on the link to intercept an outgoing client connection:

export const handlers = [
  chat.addEventListener('connection', () => {
    console.log('WebSocket client connecting...')
  }),
]

你将通过此连接监听器处理客户端和服务器事件。

¥You will be handling both client and server events from this connection listener.

重要默认值

¥Important defaults

该库实现了一组默认行为,以确保在不同的测试和开发场景中提供良好的开发者体验。你可以选择退出所有这些行为,并根据需要微调拦截。

¥The library implements a set of default behaviors to guarantee good developer experience for different testing and development scenarios. You can optot from all of these and fine-tune the interception to suit your needs.

客户端连接

¥Client connections

默认情况下,拦截的 WebSocket 连接未打开。这鼓励了模拟优先的开发,并使管理与不存在服务器的连接变得更加容易(因为在这种情况下,连接错误发生在无法捕获的计划微任务中)。你可以通过在连接监听器中调用 server.connect() 来建立实际的服务器连接。

¥By default, the intercepted WebSocket connections are not open. This encourages mock-first development and makes it easier to manage connections to non-existing servers (as the connection error in that case happens in a scheduled microtask that cannot be caught). You can establish the actual server connection by calling server.connect() in the connection listener.

客户端到服务器转发

¥Client-to-server forwarding

默认情况下,没有客户端事件会被转发到原始服务器(因为连接尚未建立)。通过 server.connect() 建立原始服务器连接后,所有客户端事件都将被转发到服务器。

¥By default, no client events are forwarded to the original server (since the connection isn’t established). Once you establish the original server connection via server.connect(), all client events will be forwarded to the server.

你可以通过在不应到达服务器的事件上调用 event.preventDefault() 来选择退出客户端到服务器的转发。

¥You can opt-out from client-to-server forwarding by calling event.preventDefault() on the events that should not reach the server.

Client-to-server forwarding

Manage the client event forwarding.

服务器到客户端转发

¥Server-to-client forwarding

默认情况下,一旦建立了实际的服务器连接,所有传入的服务器事件都会转发到客户端。你可以通过对不应到达客户端的服务器事件调用 event.preventDefault() 来选择退出此行为。

¥By default, once you establish the actual server connection, all incoming server events are forwarded to the client. You can opt-out from this behavior by calling event.preventDefault() on the server events that should not reach the client.

Server-to-client forwarding

Manage the server event forwarding.

后续步骤

¥Next steps

接下来,阅读以下部分,了解如何拦截和处理 WebSocket 客户端事件,例如 messageclose

¥Next, read the following section to learn how to intercept and handle WebSocket client events like message or close:

Client events

Intercepting and handling WebSocket client events.