WebSocket 事件流式传输
使用 GET /recordings/{recordingId}/events/ws 作为高级自定义传输方式,通过单个 WebSocket 连接流式传输 rrweb 事件。对大多数集成而言,浏览器客户端已经负责该传输、缓冲和 HTTP 回退。如果你维护自己的传输方式,请先阅读从 rrweb 迁移中的可靠性限制。
应该用 packer 还是 WebSocket 流?
两者工作在不同的层面,因此如何选择取决于你运行的是哪种后端。
packer 压缩单个事件,使它们无论存储在哪里都占用更少空间。它是库的功能,见优化存储。WebSocket 流是把事件实时传送到 rrweb Cloud 的传输方式,并以 HTTP 作为回退。使用自己的后端时由你决定是否打包。使用 rrweb Cloud 时,传输已经为你处理好了。
认证 WebSocket 连接
浏览器 WebSocket 连接在升级期间无法设置自定义 Authorization 请求头。请改为将浏览器安全的公开写入密钥放在 token 查询参数中:
const recordingId = crypto.randomUUID();
const publicWriteKey = 'public_key_rr_your_key';
const url = new URL(
`wss://api.rrweb.com/recordings/${encodeURIComponent(recordingId)}/events/ws`,
);
url.searchParams.set('token', publicWriteKey);
url.searchParams.set('contentType', 'application/x-ndjson');
const socket = new WebSocket(url);绝不要在浏览器代码或 WebSocket URL 中放置私有 API 密钥。URL 中的公开密钥仍然是凭据:WebSocket URL 可能出现在代理日志、监控、遥测和错误报告中。请遮盖 token 查询参数,并避免记录完整的 URL。
可选的查询参数包括:
contentType:application/x-ndjson、application/ndjson或application/json;默认为application/x-ndjson。contentEncoding:gzip、br或zstd;省略它表示使用 identity 编码。debug=true:回显解码后的负载数据和转发详情。请仅在隐私安全的测试录制上使用它,因为这些帧包含捕获的数据。
通过 WebSocket 发送 rrweb 事件
让 record() 创建事件对象。rrweb 会提供数值型事件 type、毫秒级 timestamp 和事件特定的 data;不要自行编造字符串事件类型或占位快照。
import { record } from '@rrweb/record';
let stopRecording: (() => void) | undefined;
const retainedEvents: unknown[] = [];
socket.addEventListener('open', () => {
stopRecording = record({
blockSelector: '[data-private]',
maskTextSelector: '[data-mask]',
maskAllInputs: true,
emit(event) {
if (socket.readyState !== WebSocket.OPEN) {
retainedEvents.push(event);
stopRecording?.();
return;
}
const frame = `${JSON.stringify(event)}\n`;
socket.send(frame);
},
});
});
function finishRecording() {
stopRecording?.();
socket.close(1000, 'capture complete');
}retainedEvents 仅用于演示发送失败时绝不能丢弃事件。它只存在于内存中,不是生产级的重试队列;如果页面终止或崩溃时不得丢失队列,请在捕获之前将队列及其已确认的位置持久化。
文本帧适用于未压缩的 NDJSON。仅当负载按照 contentEncoding 编码时才使用二进制帧。发送前使用 TextEncoder 测量编码后的字节数;摄取路由会拒绝达到或超过 1 MB 的单个帧。
确认事件已被接受
服务器在缓冲约 256 KiB 数据后,或在约一秒无活动后,会启动一次上游刷新。关闭 socket 会请求最终刷新。最终成功的结果具有以下结构:
{
"type": "upstream-result",
"ok": true,
"status": 204,
"statusText": "",
"headers": {},
"final": true
}例行成功的非最终刷新不会产生消息。失败、被隔离的行、调试输出和最终刷新可能产生消息。正常的最终结果以代码 1000 关闭;上游失败则以 1011 关闭。
这些结果消息不是逐事件的或应用级的确认。WebSocket.send() 只是把帧交给浏览器,断开连接可能让客户端无法判断哪些传输中的事件已被 Cloud 接收。重试不确定的帧可能使事件重复或乱序;丢弃它们则可能破坏快照链。
在投入生产之前,请设计持久队列、序列检查点、确认、恢复和重试行为。如果你的应用不包含这些保证,请使用浏览器客户端,或使用从 rrweb 迁移中的串行化 HTTP 传输。