ONLYOFFICE 前端实现历史记录存储与多人协作完整指南
在 ONLYOFFICE 嵌入开发中,历史记录存储与多人协作是核心需求,但很多开发者会因对 key、changesUrl 等核心概念理解不深,导致功能落地受阻。本文将从前端视角出发,详细拆解历史记录存储的实现步骤,以及多人协作的关键配置,帮你快速打通功能闭环。
一、前端实现历史记录存储功能
ONLYOFFICE 的历史记录并非由前端直接“存储”文件,而是通过对接后端接口获取版本数据、触发版本加载,并配合编辑器 API 展示历史痕迹。核心是“数据交互”而非“本地存储”,具体步骤如下:
1. 基础准备:嵌入编辑器并配置核心参数
首先需在页面中嵌入 ONLYOFFICE 编辑器,且配置中必须包含 document.key
(文档唯一标识)、editorConfig.callbackUrl
(后端接收版本回调的地址),这是后续历史记录功能的前提。
代码示例:初始化编辑器(加载最新版本)
<!-- 编辑器容器 -->
<div id="onlyoffice-editor" style="width: 100%; height: 800px;"></div><script src="https://你的DocumentServer地址/web-apps/apps/api/documents/api.js"></script>
<script>
// 从后端获取的文档基础信息(需后端接口返回)
const docInfo = {docId: "doc_123456", // 你系统中的文档IDkey: "8f9d7a6b5c4e3f2a1b0c", // ONLYOFFICE文档唯一标识(后端生成且固定)latestUrl: "https://你的存储地址/docs/latest/doc_123456.docx", // 最新版文件地址userId: "user_789", // 当前用户IDuserName: "张三" // 当前用户名
};// 编辑器配置
const editorConfig = {document: {fileType: "docx", // 文档类型(docx/xlsx/pptx等)key: docInfo.key, // 核心:文档唯一标识(不可变)url: docInfo.latestUrl, // 加载最新版文件title: "项目方案.docx" // 文档标题},editorConfig: {callbackUrl: "https://你的后端地址/api/onlyoffice/callback", // 关键:后端接收版本回调的接口user: {id: docInfo.userId,name: docInfo.userName},mode: "edit" // 编辑模式(view为只读)},events: {// 编辑器加载完成回调(可选)onReady: () => {console.log("编辑器加载完成,可操作历史记录按钮");}}
};// 初始化编辑器
const docEditor = new DocsAPI.DocEditor("onlyoffice-editor", editorConfig);
</script>
关键说明:
document.key
:同一文档的 key 必须固定不变(由后端生成并存储在数据库),否则 ONLYOFFICE 会判定为新文档,无法关联历史记录。callbackUrl
:编辑器编辑完成后,ONLYOFFICE 会将新版本的url
(最新文件地址)、changesUrl
(变更记录压缩包地址)等数据回调到该接口,后端需保存这些数据(前端无需处理回调逻辑,仅需配置地址)。
2. 实现历史记录按钮:加载版本列表
前端需自定义“历史记录”按钮,点击后通过后端接口获取该文档的所有历史版本数据(包含版本号、快照地址、changesUrl 等),并渲染成列表供用户选择。
代码示例:获取并展示历史版本列表
<!-- 历史记录按钮 -->
<button id="show-history-btn">查看历史版本</button>
<!-- 历史版本列表弹窗(示例) -->
<div id="history-modal" style="display: none; position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); border: 1px solid #ccc; padding: 20px; background: #fff;"><h3>文档历史版本</h3><ul id="history-list"></ul>
</div><script>
// 绑定历史记录按钮点击事件
document.getElementById("show-history-btn").addEventListener("click", async () => {try {// 1. 调用后端接口,获取该文档的历史版本列表const response = await fetch(`https://你的后端地址/api/documents/${docInfo.docId}/history`, {method: "GET",headers: {"Authorization": "Bearer " + localStorage.getItem("token") // 若需权限验证}});const historyList = await response.json();// 历史版本列表格式(后端需返回类似结构):// [// {// versionId: "3", // 版本号(唯一)// snapshotUrl: "https://你的存储地址/docs/history/v3/doc_123456.docx", // 该版本快照地址// changesUrl: "https://你的存储地址/docs/history/v3/changes.zip", // 该版本变更记录地址// creator: "李四", // 版本创建者// createTime: "2025-05-20 14:30:00" // 版本创建时间// },// { versionId: "2", ... },// { versionId: "1", ... }// ]// 2. 渲染历史版本列表const historyListEl = document.getElementById("history-list");historyListEl.innerHTML = "";historyList.forEach(version => {const li = document.createElement("li");li.innerHTML = `<span>${version.createTime} | 版本${version.versionId} | 创建者:${version.creator}</span><button class="open-history-btn" data-versionid="${version.versionId}" data-snapshoturl="${version.snapshotUrl}">打开该版本</button>`;historyListEl.appendChild(li);});// 3. 显示弹窗document.getElementById("history-modal").style.display = "block";// 4. 绑定“打开该版本”按钮事件document.querySelectorAll(".open-history-btn").forEach(btn => {btn.addEventListener("click", (e) => {const versionId = e.target.dataset.versionid;const snapshotUrl = e.target.dataset.snapshoturl;openHistoryVersion(versionId, snapshotUrl); // 加载历史版本的核心函数document.getElementById("history-modal").style.display = "none"; // 关闭弹窗});});} catch (error) {console.error("获取历史版本失败:", error);alert("加载历史记录出错,请重试");}
});
</script>
3. 加载指定历史版本:核心函数实现
用户选择某个历史版本后,需重新初始化编辑器(或刷新配置),传入该版本的 versionId
和 snapshotUrl
,让 ONLYOFFICE 加载对应的历史快照,而非最新版本。
代码示例:加载历史版本
/*** 加载指定历史版本* @param {string} versionId - 历史版本号* @param {string} snapshotUrl - 历史版本快照地址*/
function openHistoryVersion(versionId, snapshotUrl) {// 1. 销毁当前编辑器实例(避免多个实例冲突)if (docEditor) {docEditor.destroy();}// 2. 重新配置编辑器:指定版本号和快照地址const historyEditorConfig = {document: {fileType: "docx",key: docInfo.key, // 关键:仍使用原文档key(确保关联同一文档)url: snapshotUrl, // 加载该版本的快照文件versionId: versionId, // 关键:指定版本号(告诉ONLYOFFICE加载历史版本)title: `项目方案.docx(版本${versionId})`},editorConfig: {callbackUrl: "https://你的后端地址/api/onlyoffice/callback", // 仍用原回调地址(无需修改)user: {id: docInfo.userId,name: docInfo.userName},mode: "view" // 历史版本建议设为只读模式,避免误编辑},events: {onReady: () => {console.log(`历史版本${versionId}加载完成`);// 可选:加载变更痕迹(需配合changesUrl)loadHistoryChanges(versionId);}}};// 3. 重新初始化编辑器docEditor = new DocsAPI.DocEditor("onlyoffice-editor", historyEditorConfig);
}/*** 可选:加载历史版本的变更痕迹(高亮显示修改内容)* @param {string} versionId - 历史版本号*/
async function loadHistoryChanges(versionId) {try {// 1. 从后端获取该版本的changesUrl(或直接从历史列表缓存中获取)const response = await fetch(`https://你的后端地址/api/documents/${docInfo.docId}/history/${versionId}/changes`, {method: "GET",headers: {"Authorization": "Bearer " + localStorage.getItem("token")}});const { changesUrl } = await response.json(); // 后端返回该版本的changesUrl// 2. 调用ONLYOFFICE API加载变更痕迹// 注:需先确保编辑器已加载完成,且版本已初始化docEditor.setHistoryData({changesUrl: changesUrl, // 变更记录压缩包地址version: versionId // 对应的版本号});// 调用后,编辑器会自动用不同颜色高亮该版本的修改内容(如插入/删除的文字)} catch (error) {console.error("加载变更痕迹失败:", error);}
}
关键说明:
- 加载历史版本时,
document.key
必须与最新版本一致,否则会加载失败; versionId
是唯一标识历史版本的参数,不可省略;snapshotUrl
是该历史版本的文件快照地址(由后端保存,前端仅需从接口获取并传入);setHistoryData
方法用于加载变更痕迹,依赖changesUrl
(后端需保存 ONLYOFFICE 回调的changesUrl
并提供访问接口)。
二、前端实现多人协作功能
ONLYOFFICE 的多人协作核心是“共享同一文档标识”,即多个用户打开同一文档时,前端传入的 document.key
、document.url
、editorConfig.callbackUrl
完全一致,由 ONLYOFFICE Document Server 自动同步操作。
1. 多人协作的核心前提(前端必须满足)
配置项 | 要求 | 说明 |
---|---|---|
document.key | 所有用户一致 | 同一文档的唯一标识,后端生成并固定,确保所有用户加载同一文档 |
document.url | 所有用户一致 | 指向同一文件(建议用带时效性的预签名 URL,避免未授权访问) |
editorConfig.callbackUrl | 所有用户一致 | 确保所有用户的编辑操作最终回调到同一后端接口,保存到同一文件 |
editorConfig.user | 每个用户传入自己的 ID 和名称 | 用于在编辑器中显示“谁正在编辑”“谁做了修改” |
2. 多人协作的前端实现步骤
步骤1:确保用户获取到相同的文档核心参数
无论哪个用户打开同一文档,前端从后端获取的 docInfo
中,key
和 latestUrl
必须完全一致(后端通过文档 ID 查询数据库返回,而非前端生成)。
示例:用户 A 和用户 B 打开同一文档 doc_123456
,后端返回的 docInfo
均为:
const docInfo = {docId: "doc_123456",key: "8f9d7a6b5c4e3f2a1b0c", // 两人的key完全一致latestUrl: "https://你的存储地址/docs/latest/doc_123456.docx", // 两人的url完全一致userId: "user_789", // 用户A的ID// 或 userId: "user_012"(用户B的ID)
};
步骤2:初始化编辑器(与加载最新版本一致)
所有用户的编辑器配置除 editorConfig.user
不同外,其他参数(key
、url
、callbackUrl
)完全一致,示例代码同“一、1 基础准备”中的编辑器初始化代码。
此时,ONLYOFFICE 会自动检测到“同一 key 的文档被多个用户打开”,触发协作模式:
- 编辑器顶部会显示“当前有 X 人正在编辑”;
- 每个用户的光标会显示对应的用户名(如“张三的光标”);
- 实时同步输入内容(如用户 A 输入文字,用户 B 秒级看到);
- 支持段落锁定(用户编辑某段时,其他用户无法同时编辑该段,避免冲突)。
步骤3:协作中的历史记录同步
多人协作时,编辑完成后(如用户关闭文档、或编辑器自动保存),ONLYOFFICE 会将新版本数据回调到后端,后端保存最新 url
、changesUrl
和版本号。
其他用户下次打开文档时,前端从后端获取的 latestUrl
会自动更新为最新版本,历史版本列表也会包含所有用户的编辑记录(如“李四修改了版本 3”“张三修改了版本 4”),实现历史记录的全员同步。
3. 前端协作功能的注意事项
- 避免前端生成 key:key 必须由后端生成并存储,前端仅负责传递,防止用户篡改 key 访问他人文档;
- 权限控制:前端需先通过后端接口验证用户是否有该文档的访问权限,再加载编辑器(避免未授权用户协作);
- 网络稳定性:若网络中断,ONLYOFFICE 会自动缓存本地编辑内容,网络恢复后同步到服务器(前端无需额外处理);
- 实时状态显示:可通过
events.onUserConnected
/onUserDisconnected
事件,在页面上显示“谁加入/离开编辑”,提升协作体验:const editorConfig = {// ... 其他配置events: {onUserConnected: (e) => {console.log(`用户 ${e.data.name} 加入编辑`);// 可在页面上显示提示:“李四已加入协作”},onUserDisconnected: (e) => {console.log(`用户 ${e.data.name} 离开编辑`);}} };
三、总结
前端实现 ONLYOFFICE 历史记录存储与多人协作,核心是“对接后端接口传递正确参数”,而非复杂的本地逻辑:
- 历史记录存储:前端负责“触发获取版本列表”“加载指定版本”“展示变更痕迹”,后端负责保存
key
、snapshotUrl
、changesUrl
等核心数据; - 多人协作:前端确保所有用户的
key
、url
、callbackUrl
一致,仅传递不同的用户信息,其余同步逻辑由 ONLYOFFICE 自动完成。
只要遵循“参数统一、接口对接、后端存储”的原则,即可快速实现稳定的历史记录与多人协作功能。