WebSocket 长连接采集¶
从 RUM SDK 3.3.6 开始,可以把浏览器中的原生 WebSocket 连接汇总为 RUM Resource,用于分析握手、消息流量、入站空闲、发送积压和关闭状态。
该能力目前是实验功能,默认关闭。SDK 不读取或上传 WebSocket 消息正文。
开启采集¶
NPM¶
import { datafluxRum } from "@cloudcare/browser-rum"
datafluxRum.init({
applicationId: "<APPLICATION_ID>",
site: "<PUBLIC_OPENWAY_URL>",
clientToken: "<CLIENT_TOKEN>",
service: "websocket-client",
env: "production",
version: "1.0.0",
sessionSampleRate: 100,
enableExperimentalFeatures: ["track_websockets"],
})
精简 RUM 包使用相同配置:
CDN¶
<script
src="https://static.guance.com/browser-sdk/v3/dataflux-rum.js"
type="text/javascript"
></script>
<script>
window.DATAFLUX_RUM &&
window.DATAFLUX_RUM.init({
applicationId: "<APPLICATION_ID>",
site: "<PUBLIC_OPENWAY_URL>",
clientToken: "<CLIENT_TOKEN>",
service: "websocket-client",
env: "production",
version: "1.0.0",
sessionSampleRate: 100,
enableExperimentalFeatures: ["track_websockets"],
})
</script>
以上示例使用公网 OpenWay。使用 DataKit 直连时,将 site 和 clientToken
替换为 datakitOrigin,不要同时配置两种上报地址。
enableExperimentalFeatures 必须是数组。直接写成字符串
"track_websockets" 不会开启采集。
初始化时机¶
RUM 必须在业务创建 WebSocket 连接之前初始化:
datafluxRum.init({
// 其他配置
enableExperimentalFeatures: ["track_websockets"],
})
const socket = new WebSocket("wss://example.com/socket")
以下连接不会被采集:
- RUM 初始化前已经创建的连接;
- 使用初始化前缓存的原始
WebSocket构造函数创建的连接; - Web Worker 或 Service Worker 内创建的连接;
- 不经过
window.WebSocket的其他传输实现; WebSocketStream创建的连接。
开启采集不会改变原生 WebSocket 的构造方式、静态常量、instanceof、
业务事件监听和 send() 返回行为。
采集模型¶
每个 WebSocket Session 分段生成一个 RUM Resource:
Resource 在以下时机生成:
- 浏览器收到 WebSocket
close事件; - 当前 RUM Session 到期;
- 页面触发
beforeunload; - SDK 停止当前采集实例。
WebSocket 是长连接。连接仍保持打开时,Network 中暂时没有最终 RUM Resource 属于正常现象;SDK 当前不会周期性上报连接快照。
页面刷新、关闭或跳转时,SDK 会在 beforeunload 阶段尽力结算并发送。如果页面
进程被强制结束、浏览器崩溃或设备断电,JavaScript 可能没有执行机会,最后一条
连接 Resource 仍可能丢失。
正常关闭¶
浏览器收到 close 后:
事件包含关闭码、关闭原因和 was_clean。
Session 到期¶
Session 到期时,仍打开的连接会按当前数据结算:
此时业务 WebSocket 不会被关闭,因此关闭码、关闭原因和 was_clean 可能不存在。
新 Session 建立后,SDK 会为同一物理连接开启新的统计分段,保留相同
connection_id,并重置消息计数和分段时间。
Session 过期但尚未续期期间的消息不会计入任一 Session。此期间新建且在续期时 仍保持打开的连接,会从新 Session 的续期时刻开始统计。
页面卸载¶
页面触发 beforeunload 时:
连接不一定触发浏览器 close 事件,因此关闭字段可能不存在。
握手失败¶
连接从未触发 open 就进入 close 时:
此时 setup_duration 表示从构造连接到关闭或 Session 结算的时间,不代表成功
握手耗时。浏览器通常使用关闭码 1006 表示异常关闭,具体值以浏览器事件为准。
消息统计¶
SDK 只统计消息数量和字节数,不采集正文:
| 消息类型 | 字节计算方式 |
|---|---|
| string | UTF-8 字节数 |
ArrayBuffer |
byteLength |
TypedArray、DataView |
当前 view 的 byteLength |
Blob |
size |
| 无法识别的类型 | 0 |
例如字符串 你好 按 UTF-8 统计为 6 字节,而不是 JavaScript 字符串长度 2。
View 归属¶
一个 WebSocket Session 分段可能跨越多个 RUM View。Resource 额外记录:
start_view_id:当前分段开始时所在 View;end_view_id:关闭或结算时所在 View。
分段跨页面时,这两个 ID 可以不同。Resource 仍按分段开始时间进入 RUM 事件管道。
上报字段¶
beforeSend 中可以读取 event.resource.websocket;最终 intake 会把字段转换为
resource_websocket_*。
基础 Resource 字段¶
beforeSend 路径 |
intake 字段 | 说明 | 单位 |
|---|---|---|---|
resource.type |
resource_type |
固定为 websocket |
- |
resource.url |
resource_url |
浏览器解析后的 ws:// 或 wss:// URL |
- |
resource.url_host |
resource_url_host |
URL host | - |
resource.url_path |
resource_url_path |
URL path | - |
resource.url_query |
resource_url_query |
URL query 参数 | - |
resource.duration |
duration |
当前 Session 分段时长 | ns |
WebSocket Resource 没有 HTTP response,因此没有 resource_status、
resource_method、TTFB、下载大小或 HTTP timing。
连接字段¶
resource.websocket.* |
intake 字段 | 说明 | 单位 |
|---|---|---|---|
connection_id |
resource_websocket_connection_id |
物理连接唯一 ID,跨 Session 分段保持不变 | - |
handshake_succeeded |
resource_websocket_handshake_succeeded |
是否收到 open |
boolean |
start_time |
resource_websocket_start_time |
当前分段开始时间 | Unix ms |
end_time |
resource_websocket_end_time |
关闭或结算时间 | Unix ms |
start_view_id |
resource_websocket_start_view_id |
分段开始时的 View ID | - |
end_view_id |
resource_websocket_end_view_id |
连接结束时的 View ID | - |
tracking_end_reason |
resource_websocket_tracking_end_reason |
close_event、session_end 或 page_exit |
- |
protocol |
resource_websocket_protocol |
服务端协商的子协议 | - |
setup_duration |
resource_websocket_setup_duration |
首段为构造到 open 的时间;续期分段为 0 |
ns |
消息字段¶
resource.websocket.* |
intake 字段 | 说明 | 单位 |
|---|---|---|---|
messages_in.count |
resource_websocket_messages_in_count |
入站消息数量 | count |
messages_in.size |
resource_websocket_messages_in_size |
入站消息总字节数 | byte |
messages_out.count |
resource_websocket_messages_out_count |
成功调用 send() 的次数 |
count |
messages_out.size |
resource_websocket_messages_out_size |
出站消息总字节数 | byte |
time_to_first_message_in |
resource_websocket_time_to_first_message_in |
open 到首条入站消息 |
ns |
time_to_first_message_out |
resource_websocket_time_to_first_message_out |
open 到首条出站消息 |
ns |
last_message_in_at |
resource_websocket_last_message_in_at |
最后一条入站消息时间 | Unix ms |
longest_inbound_silence |
resource_websocket_longest_inbound_silence |
相邻入站消息之间的最长间隔 | ns |
inbound_idle_duration_before_close |
resource_websocket_inbound_idle_duration_before_close |
最后一条入站消息到关闭或结算的时间 | ns |
buffered_amount_max |
resource_websocket_buffered_amount_max |
每次调用 send() 前观察到的 bufferedAmount 峰值 |
byte |
buffered_amount_max 是调用 send() 前的采样峰值,不是浏览器发送队列的连续监控值。
关闭字段¶
resource.websocket.* |
intake 字段 | 说明 |
|---|---|---|
close_code |
resource_websocket_close_code |
浏览器 CloseEvent 的关闭码 |
close_reason |
resource_websocket_close_reason |
关闭原因 |
was_clean |
resource_websocket_was_clean |
浏览器是否认为连接正常关闭 |
Session 到期或页面卸载结算时,这些字段可能不存在。
使用 beforeSend¶
可以检查、补充或过滤 WebSocket Resource:
datafluxRum.init({
// 其他配置
enableExperimentalFeatures: ["track_websockets"],
beforeSend(event, domainContext) {
if (
event.type === "resource" &&
event.resource?.type === "websocket"
) {
event.context = {
...event.context,
socket_channel: "notifications",
}
console.debug(
"WebSocket completed",
event.resource.websocket,
domainContext?.webSocket
)
}
return true
},
})
WebSocket Resource 的 domainContext 包含:
domainContext 只在 beforeSend 回调中使用,不会上传。
返回 false 可以丢弃指定连接:
beforeSend(event) {
if (
event.type === "resource" &&
event.resource?.type === "websocket" &&
event.resource.url.includes("/health-stream")
) {
return false
}
return true
}
隐私与安全¶
SDK 会采集完整 WebSocket URL,并解析 URL query。不要在 URL 中放置密码、长期 Token、身份证号等敏感值。
开启采集不会绕过页面 CSP connect-src、服务端 Origin 校验或其他浏览器安全
策略,也不会向握手请求注入自定义 trace header。
第三方库只要在 RUM 初始化后调用 window.WebSocket,底层连接就会被采集:
- 自动重连每创建一次新连接,就生成新的
connection_id和 Resource; - 一个连接复用多个业务 topic 时,SDK 只提供连接级汇总;
- HTTP long polling 阶段仍按 XHR 或 fetch Resource 采集。
验证接入¶
- 打开浏览器开发者工具,确认业务 WebSocket 已连接并产生消息。
- 主动执行
socket.close(1000, "done")。 - 在 Network 中过滤
/v1/write/rum。 - 在请求数据中查找
resource_type=websocket。 - 检查
handshake_succeeded、消息数量、字节数和关闭字段。
连接一直不关闭时,可以等待 Session 到期后检查
tracking_end_reason=session_end。刷新页面时应看到
tracking_end_reason=page_exit;该发送属于页面退出阶段的尽力上报。
常见问题¶
配置后没有 WebSocket Resource¶
按以下顺序检查:
enableExperimentalFeatures是否为包含"track_websockets"的数组;- RUM 是否在连接创建前初始化;
- 当前 Session 是否命中
sessionSampleRate; - 连接是否已关闭,或 Session 是否已经到期;
beforeSend是否返回了false;- 连接是否由 Worker 创建。
已收到 WebSocket error,但暂时没有 Resource¶
SDK 在 close 或 Session 结算时生成最终事件,不会在 error 事件上单独结算。
handshake_succeeded=false¶
浏览器没有触发 open。检查 WebSocket URL、TLS 证书、CSP connect-src、
反向代理 Upgrade 配置、服务端 Origin 校验和鉴权。
消息 size 为 0¶
确认数据类型是 string、ArrayBuffer、TypedArray、DataView 或 Blob。
SDK 不会序列化任意对象来估算大小。
看不到 HTTP 状态码¶
浏览器 WebSocket API 不向页面暴露握手 HTTP 状态码,因此 WebSocket Resource
没有 resource_status。