# 修改 WebSocket 消息

> 在 Proxyman Scripting 中使用 onWebsocket 实时编辑、丢弃或发送 WebSocket（WS/WSS）消息，支持双向传输，支持文本和二进制消息。

## 1. 这是什么？ {#1-whats-it}

勾选 **Modify WebSocket Messages** 选项后，脚本中的 `onWebsocket()` 函数即可实时修改 WebSocket 消息。只需几行 JavaScript，你可以：

* 编辑消息，例如修改 JSON 字段或替换文本。
* 丢弃消息，使对端永远收不到它。
* 向客户端或服务器发送新消息。
* 在两端同时关闭 WebSocket。

它支持 WS 和 WSS，并且双向生效：从客户端到服务器，以及从服务器到客户端。

> **备注:** **macOS 版 Proxyman 26.2.0 或更高版本**和 **Windows/Linux 版 Proxyman 26.1.0 或更高版本**支持 Modify WebSocket Messages，iOS 不支持。

<figure class="gb-embed gb-embed--video"><video controls playsinline muted preload="metadata" width="1920" height="1080" src="https://proxyman.com/assets/video/modify-websocket-messages-demo.mp4" aria-label="一条 Proxyman Scripting 规则正在编辑并丢弃实时 WebSocket 的消息"></video><figcaption><p>服务器发送的是真实的 BTC 价格，但应用收到的是 $1。包含密码的消息被丢弃，应用还收到了脚本发出的警告。</p></figcaption></figure>

## 2. 面临的问题 {#2-the-problem}

聊天、交易、游戏和实时仪表盘等应用使用 WebSocket 获取实时数据，测试起来很困难：

* **你无法控制服务器。** 它发送的是真实数据。要让它发送边界情况，例如价格为 0 或错误消息，就得修改服务器代码。
* **有些情况很难复现。** 消息丢失、异常回复或连接断开，往往不会在你需要的时候出现。
* **其他工具无法修改消息。** [Breakpoint](https://proxyman.com/docs/zh-cn/advanced-features/breakpoint) 和 [Map Local](https://proxyman.com/docs/zh-cn/advanced-features/map-local) 作用于 HTTP 握手阶段，而不是握手之后的消息。未启用该选项时，`onWebsocket()` 只能读取消息。

## 3. 优势 {#3-benefits}

* 无需修改服务器，即可测试应用应处理的每一种消息。
* 模拟服务器回复：使用 `sendToClient()` 回复客户端发出的消息，服务器永远不会收到它。
* 在数据发送到服务器之前，隐藏敏感数据或拦截统计分析事件。
* 模拟连接断开，测试应用如何重新连接。
* 只有匹配规则的 WebSocket 会等待脚本处理，其他流量照常传输。

## 4. 如何使用？ {#4-how-to-use-it}

1. 抓取你的 WebSocket 连接。对于 `wss://`，请像处理 HTTPS 一样，为该域名启用 [SSL Proxying](https://proxyman.com/docs/zh-cn/basic-features/ssl-proxying)。
2. 右键点击 `ws://` 或 `wss://` 请求 -> **Tools** -> **Scripting…**。Proxyman 会创建一条已填入 URL 的规则，以及一个包含 `onWebsocket()` 的脚本。
3. 保持 **Request** 已勾选，并勾选 **Modify WebSocket Messages**。
4. 编写 `onWebsocket()` 代码，然后点击 **Save & Activate**（macOS 按 ⌘S，Windows/Linux 按 Ctrl+S）。
5. 重新连接 WebSocket。Proxyman 在 WebSocket 连接时读取该选项，而不是在每条消息到达时读取。

![Proxyman Script Editor，已勾选 Modify WebSocket Messages，并包含 onWebsocket() 脚本](https://proxyman.com/docs/assets/script-editor-modify-websocket-messages.jpg)

_在 Script Editor 中勾选 Modify WebSocket Messages_

这段脚本会将服务器发来的每个 BTC 价格改为 $1，并丢弃客户端发出的包含密码的消息：

```javascript
function onWebsocket(context, url, request, response, message) {
  // Only change text messages. Binary, ping, pong, and close messages pass through
  if (message.type !== "text") {
    return message;
  }

  const json = JSON.parse(message.data);

  // 1. Server -> client: every BTC price becomes $1
  if (message.from === "server" && json.type === "price") {
    json.price = 1;
    json.note = "edited by Proxyman";
    message.data = JSON.stringify(json);
    return message;
  }

  // 2. Client -> server: drop a message with a password, and warn the client
  if (message.from === "client" && json.text.includes("password")) {
    sendToClient(JSON.stringify({ type: "warning", text: "Proxyman blocked a password" }));
    return null;
  }

  // 3. Everything else: send it as it is
  return message;
}
```

**Websocket** 标签页会显示被编辑的消息、脚本发送的消息，以及被丢弃的消息：

![Proxyman 主窗口，显示 ws://localhost:3456/prices 请求及其被编辑的 WebSocket 消息](https://proxyman.com/docs/assets/websocket-tab-edited-messages.jpg)

_在 Websocket 标签页中查看被编辑和被丢弃的消息_

如果想跟着步骤操作，并自己运行一个本地 WebSocket 服务器，请阅读 [如何使用 Scripting 修改 WebSocket 消息](https://proxyman.com/posts/2026-10-23-modify-websocket-messages-with-scripting)。

## 5. onWebsocket() 的返回值 {#5-what-onwebsocket-returns}

启用该选项后，Proxyman 会暂存每条文本和二进制消息，直到 `onWebsocket()` 返回。你的返回值决定后续操作：

| 在 `onWebsocket()` 中 | 结果 |
| --- | --- |
| `return message` | 发送消息（包括你做的修改）。 |
| `return null` | 丢弃消息，对端永远收不到它。 |
| 不返回任何值 | 发送原始消息。 |
| `abort()` | 在两端关闭 WebSocket。 |
| `sendToClient(data)` / `sendToServer(data)` | 发送新消息。String 发送文本消息，`Uint8Array` 发送二进制消息。 |

`message` 对象包含以下字段：

| 字段 | 值 |
| --- | --- |
| `message.from` | `"client"` 或 `"server"`。 |
| `message.type` | `"text"`、`"binary"`、`"ping"`、`"pong"` 或 `"close"`。 |
| `message.data` | 消息的文本内容。修改它即可编辑文本消息。 |
| `message.rawData` | 二进制消息的字节，类型为 `Uint8Array`。设置一个新的 `Uint8Array` 即可编辑二进制消息。 |
| `message.closeCode` | 数字，仅 close 消息可用，例如 `1000`。 |

其他参数请参阅 [Scripting 的 WebSocket 说明](https://proxyman.com/docs/zh-cn/scripting/script#41-scripting-with-websocket)。

> **备注:** 该选项默认关闭。关闭时，`onWebsocket()` 的行为与以前一样：只读取消息，从不延迟消息。

## 6. 模板 {#6-templates}

无需从零编写脚本。在 Script Editor 中点击 **Templates**，然后搜索 “websocket”：

* **Log WebSocket Messages**：在 Console Log 中打印每条消息。它只读取消息。
* **Modify JSON WebSocket Messages**：修改服务器发来的 JSON 消息中的某个字段。
* **Replace Text in WebSocket Messages**：在两个方向上查找并替换文本。
* **Drop WebSocket Messages**：丢弃匹配正则表达式的消息，例如统计分析事件。
* **Reply to a WebSocket Message**：使用 `sendToClient()` 回复客户端的消息，服务器永远不会收到它。
* **Simulate a WebSocket Disconnect**：在收到若干条消息后关闭 WebSocket。

点击 **Replace** 即可使用模板。Proxyman 还会自动勾选所需的选项，包括 **Modify WebSocket Messages**。

![Proxyman 中的 Script Templates 面板，已筛选出 WebSocket 模板](https://proxyman.com/docs/assets/websocket-script-templates.jpg)

_Script Editor 中的 WebSocket 模板_

更多示例请参阅 [Snippet Code](https://proxyman.com/docs/zh-cn/scripting/snippet-code#modify-websocket-messages-with-onwebsocket) 页面。

## 7. 注意事项 {#7-good-to-know}

* 你可以编辑和丢弃文本消息及二进制消息。Ping、pong 和 close 消息始终会被发送：`onWebsocket()` 可以读取它们，但其返回值会被忽略。
* 消息保持其类型不变：你无法将文本消息改为二进制消息。
* 如果脚本抛出错误，或在 30 秒内没有返回，Proxyman 会发送原始消息，并在 Console Log 中打印错误。
* `onWebsocket()` 之外的代码每个连接运行一次，因此脚本顶部的计数器会分别统计每个连接的消息数。
* 通过 `sendToClient()` 和 `sendToServer()` 发送的消息不会再次触发 `onWebsocket()`，因此回复消息的脚本不会陷入无限循环。
* 当多个启用了该选项的脚本匹配同一个 WebSocket 时，它们会按顺序运行：每个脚本都接收前一个脚本的返回结果。被丢弃的消息不会传给后面的脚本。
* 超过 16 MB 的消息会原样发送，不经过脚本处理。
* 支持 `async` 函数，因此你可以在 `onWebsocket()` 中使用 `await` 和 [$http](https://proxyman.com/docs/zh-cn/scripting/async-await-request)。
* AI 智能体可以通过 [Proxyman MCP](https://proxyman.com/docs/zh-cn/mcp) 创建相同的规则：`create_scripting_rule` 接受 `modify_websocket_messages: true` 参数。

## 8. 故障排除 {#8-troubleshooting}

### 消息没有变化 {#the-messages-dont-change}

* 检查是否已勾选 **Modify WebSocket Messages**，然后点击 **Save & Activate**（macOS 按 ⌘S，Windows/Linux 按 Ctrl+S）。
* 重新连接 WebSocket。该选项在 WebSocket 连接时读取。
* **Request** 和 **Response** 中至少勾选一项。两者都未勾选的规则完全不会运行，包括 `onWebsocket()`。
* 修改后请返回 `message`。如果不返回，Proxyman 会发送原始消息。
* 在 Script Editor 中打开 Console Log，查看是否有错误。

### 在 Proxyman 中看不到我的 WebSocket {#i-cant-see-my-websocket-in-proxyman}

请按照你所用平台的 [WebSocket](https://proxyman.com/docs/zh-cn/advanced-features/websocket) 指南操作。许多应用和库会对 `localhost` 跳过代理。
