构建回放界面
请将应用的授权边界置于 rrweb Cloud 之前。私有 API 密钥(secret_key_rr_*)拥有完整的读写权限。它必须保留在 受信服务器或密钥管理器中。绝不要在浏览器代码中暴露私有 API 密钥。 公开写入密钥可以摄取事件,但无法获取录制。
下面的模式分为两部分:你的服务器先对查看者进行身份验证,并向 Cloud 请求一个受限的事件 URL,然后浏览器下载该事件流并 将其交给 rrwebPlayer。
从受信服务器获取回放访问权限
将私有 API 密钥存储为服务器密钥,应用你自己的授权检查,然后暴露一个向 rrweb Cloud 请求限定范围的已签名事件 URL、并只返回回放界面所需元数据字段的服务器路由。
将 RRWEB_CLOUD_PRIVATE_API_KEY 存储为服务器密钥。其值以 secret_key_rr_ 开头;不要硬编码。在应用你自己的授权检查之后,暴露一个 服务器路由,例如 /api/replay-access/:recordingId,运行以下函数:
const rrwebCloudApi = 'https://api.rrweb.com';
export async function getReplayAccess(recordingId) {
const detailUrl = new URL(`/recordings/${recordingId}`, rrwebCloudApi);
detailUrl.searchParams.set('includeSignedUrls', 'true');
const response = await fetch(detailUrl, {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.RRWEB_CLOUD_PRIVATE_API_KEY}`,
Accept: 'application/json',
},
});
if (!response.ok) {
throw new Error(`rrweb Cloud returned ${response.status}`);
}
const recording = await response.json();
if (!recording.links.eventsSigned) {
throw new Error('A signed event URL was not available');
}
return {
recordingId: recording.recordingId,
metadata: browserSafeMetadata(recording.metadata),
eventsUrl: new URL(recording.links.eventsSigned, rrwebCloudApi).toString(),
};
}
// Metadata can carry server-only fields such as support case ids or account
// segments. Return only the keys the replay UI needs.
const browserSafeMetadataKeys = ['environment', 'app_version', 'feature_flag'];
function browserSafeMetadata(metadata = {}) {
return Object.fromEntries(
Object.entries(metadata).filter(([key]) =>
browserSafeMetadataKeys.includes(key),
),
);
}这使用了获取录制。其正常 响应为 { recordingId, metadata, links };设置 includeSignedUrls=true 会在配置签名后添加 eventsSigned。仅在验证已登录的应用用户有权查看该录制之后 才返回结果,并对返回的元数据键做白名单:应用元数据 可能包含不得到达浏览器的仅限服务器使用的分类信息。
你也可以在服务器上请求获取录制 事件,并代理返回的顶层事件 数组。受限 URL 可以避免让事件正文经过你的服务器,而代理则能让你的服务器 对响应有更严格的控制。
在浏览器中初始化播放器
安装播放器及其样式表:
npm install rrweb-player在模块运行之前,向页面添加挂载元素:
<div id="replay"></div>该示例渲染一个 1024×576 像素的播放器。请确保周围布局能够 容纳该尺寸,或者选择适合你回放视图的尺寸。
然后向你自己的已认证路由请求回放访问权限,获取受限事件 数组,并初始化播放器。此示例使用有效的录制 UUID, 且不会使用写入凭据读取数据:
import rrwebPlayer from 'rrweb-player';
import 'rrweb-player/dist/style.css';
const replayTarget = document.querySelector('#replay');
if (!(replayTarget instanceof HTMLElement)) {
throw new Error('Replay mount element #replay was not found');
}
const recordingId = '550e8400-e29b-41d4-a716-446655440000';
const accessResponse = await fetch(`/api/replay-access/${recordingId}`, {
credentials: 'same-origin',
});
if (!accessResponse.ok) {
throw new Error(`Replay access failed: ${accessResponse.status}`);
}
const { eventsUrl } = await accessResponse.json();
const eventsResponse = await fetch(eventsUrl);
if (!eventsResponse.ok) {
throw new Error(`Event retrieval failed: ${eventsResponse.status}`);
}
const events = await eventsResponse.json();
if (!Array.isArray(events) || events.length === 0) {
throw new Error('The recording has no replayable events');
}
const player = new rrwebPlayer({
target: replayTarget,
props: {
events,
width: 1024,
height: 576,
autoPlay: false,
showController: true,
skipInactive: true,
mouseTail: true,
},
});当其容器被移除时,使用 player.$destroy() 销毁组件。 有关控件、插件、大型事件流和故障诊断,请继续阅读 高级回放与故障排查。