Skip to content

[BUG] document:open-buffer 无法打开 docx 文件,错误码 -85 #113

Closed

Description

@zjhtsgr

描述
在 Qt WebEngine (PySide6) 环境中,通过 document:open-buffer 消息传递 Base64 编码的 docx 文件数据时,OnlyOffice 编辑器显示错误:
错误码:-85
错误描述:在打开文件时发生了错误。
文件内容对应于以下格式之一:pdf/djvu/xps/oxps,但该文件的扩展名不一致:docx。

复现步骤
使用 PySide6 QWebEngineView 加载 document 项目
从 Python 端通过 QWebEngineView.page().runJavaScript() 发送 document:open-buffer 消息
Python 端将 docx 文件读取为 bytes,转换为 Base64 后传递
编辑器加载后触发 onError 事件,错误码 -85

日志
[Embed API] Base64 first 50 chars: UEsDBAoAAAAAAIdO4kA...
[Embed API] Decoded file header (hex): 50 4b 03 04
[Embed API] ✅ Valid DOCX file detected (PK header)
[Embed API] Decoded Base64 to ArrayBuffer, size: 10216
[converter] Final documentData.bin header (hex): 50 4b 03 04
[converter] ✅ binData is valid DOCX
[OnlyOffice] Creating new editor instance for: New_Document.docx type: docx
[OnlyOffice] onAppReady triggered
[OnlyOffice] binData type in onAppReady: object
[OnlyOffice] onError: [object Object]
[OnlyOffice] onError details: {"target":{"frameOrigin":"http://127.0.0.1:5000"},"data":{"errorCode":-85,"errorDescription":"在打开文件时发生了错误。
文件内容对应于以下格式之一:pdf/djvu/xps/oxps,但该文件的扩展名不一致:docx。"}}

关键观察:
embed-api.ts 正确解码 Base64 为 ArrayBuffer(文件头 50 4b 03 04)
converter.ts 正确传递 binData
onlyoffice-editor.ts 中 binData type in onAppReady: object —— binData 在 onAppReady 中变成了普通对象,而不是 ArrayBuffer

环境信息
项目 版本
OnlyOffice API 7.4.1
Qt WebEngine PySide6 (Qt 6.x)
Python 3.12+
Node.js 20.19.0+
pnpm 11.4.0

相关文件
embed-api.ts (makeArrayBufferFromPayload):
async function makeArrayBufferFromPayload(payload: Record<string, any>): Promise {
if (payload.data && typeof payload.data === 'string') {
const binaryString = atob(payload.data);
const bytes = new Uint8Array(binaryString.length);
for (let i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
return bytes.buffer; // 返回 ArrayBuffer
}
}

onlyoffice-editor.ts (createEditorInstance):
export function createEditorInstance(config: {
fileName: string;
fileType: string;
binData: any; // 期望 ArrayBuffer
media?: any;
readonly?: boolean;
}): Promise {
// binData 在 onAppReady 中变成了 object,而不是 ArrayBuffer
}

可能的根本原因
1、Qt WebEngine 的 postMessage 序列化机制:Qt WebEngine 在处理 postMessage 时,ArrayBuffer 类型可能被转换为普通对象
2、window.DocsAPI.DocEditor 的 onAppReady 回调中,binData 丢失了类型信息
3、Vite 编译优化导致代码行为改变

期待行为
document:open-buffer 应正确打开 docx 文件
binData 在 onAppReady 中应保持为 ArrayBuffer 类型

Activity

  1. chaxus commented on Aug 4, 2026

    @chaxus
    Member

    @zjhtsgr 看起来都分析到原因了,可以提个 pr 来处理吗

  2. zjhtsgr commented on Aug 4, 2026

    @zjhtsgr
    Author

    感谢建议。
    我尽管分析出原因,并且在本地反复修改过 onlyoffice‑editor.ts、embed‑api.ts、converter.ts 这些文件,但始终没能修复完成。
    希望技术更擅长的朋友可以来修复这段代码。我会持续关注该 issue,如果其他人愿意提交 PR,我会非常感谢。

  3. chaxus commented on Aug 4, 2026

    @chaxus
    Member

    @zjhtsgr 谢谢你这么细致的排查和记录。照着你贴的日志和分析,找到了一个大概率的根因:asc_openDocument 把转换后的文档内容作为原始 ArrayBuffer 通过 postMessage 传给 OnlyOffice 内部的编辑器 iframe,这一步依赖宿主环境对二进制类型的结构化克隆支持——嵌入式 WebView(比如 Qt WebEngine)在这块历史上确实容易出问题。项目里"新建空白文档"那条路径一直传的是 Base64 字符串且工作正常,所以这次改成统一走 Base64,理论上能绕开这个坑;顺带也把 document:open-buffer 之前完全不支持 Base64 payload 的缺口补上了。

    PR 在这里:#115,细节和分析过程写在 PR 里链的那篇 exploration 文档里了。

    不过我这边没有 Qt WebEngine 环境,没法端到端复现你遇到的场景,所以这个修复目前只过了单元测试,还没有真实验证过。方不方便麻烦你在你的 PySide6 环境里拉这个分支(fix/issue-113-embed-buffer-base64)试一下,看看还会不会报 -85?如果还是不行,麻烦把新的日志贴一下,我们再接着往下查。先谢谢你了 🙏

  4. zjhtsgr commented on Aug 6, 2026

    @zjhtsgr
    Author

    Issue #113 验证报告(最终版)
    一、问题
    在 Qt WebEngine (PySide6) 环境下,通过 document:open-buffer 传递 Base64 编码的 docx 文件,OnlyOffice 报错 -85:
    "文件内容对应于以下格式之一:pdf/djvu/xps/oxps,但该文件的扩展名不一致:docx。"

    二、官方修复内容
    官方针对 #113 的修复方案:
    lib/embed-api.ts:makeFileFromPayload 新增 payload.base64 处理分支
    lib/onlyoffice-editor.ts:onAppReady 中将 binData 统一转为 Base64 字符串再发送 asc_openDocument
    类型定义:buf 类型从 ArrayBuffer 放宽为 ArrayBuffer | string
    修复逻辑:Base64 字符串在 postMessage 中不会失真,因此将二进制数据转成 Base64 后再发送,绕开 ArrayBuffer 跨边界失真问题。

    三、验证结果
    验证环境: Python 3.12 + PySide6 6.7.0 + Qt WebEngine,测试文件 10216 bytes
    关键日志(已在 api.js 中添加日志):
    [JS Log] [API.JS] sendCommand (internal) called, command: asc_openDocument
    [JS Log] [API.JS] sendCommand called, command: asc_openDocument
    [JS Log] [API.JS] OnlyOffice error code: -85
    关键发现:
    sendCommand 被正确调用,asc_openDocument 命令已发送
    onAppReady 被调用了 4 次(重复创建编辑器实例)
    asc_openDocument 被发送了 4 次
    最终 OnlyOffice 内部返回 -85 错误
    数据在到达 api.js 的 sendCommand 之前全部正确,但 -85 错误来自 OnlyOffice 内部 iframe 的响应。

    四、根本原因
    window.editor.sendCommand 调用 OnlyOffice SDK 的 sendCommand,数据通过 postMessage 发送给内部 iframe,OnlyOffice 内部解析 buf 时将其错误识别为 PDF 格式。
    问题发生在 OnlyOffice SDK 内部,不在 document 项目层面:
    document 项目 → window.editor.sendCommand
    → api.js (sendCommand) → postMessage
    → OnlyOffice 内部 iframe → 解析 buf → 判断为 PDF → 报 -85

    五、需要官方进一步排查
    检查 api.js 中 i() 函数的 o.data?.event 条件分支:当 o.data 包含 buf 但不包含 event 时,o 不会被 JSON.stringify,走 postMessage 结构化克隆路径。但 buf 是 Base64 字符串,结构化克隆应该安全。
    在 OnlyOffice 内部 iframe 的消息接收端添加日志:需要确认 buf 在接收端是否保持为正确的 Base64 字符串,还是被误解析为其他格式。
    检查 Qt WebEngine 对 postMessage 的特殊处理:Qt WebEngine 可能对跨 iframe 的 postMessage 做了额外的序列化处理。
    如果数据在 postMessage 过程中被损坏,需要在 OnlyOffice SDK 层面修复,而不是在 document 项目层面。

    六、结论
    官方修复未解决 #113。 数据在 sendCommand 发送前是正确的(Base64 长度 13624),但 OnlyOffice 内部解析时出错。问题根源在 OnlyOffice SDK 内部的 postMessage 接收和解析逻辑,需要 OnlyOffice 官方在 SDK 层面排查修复。

  5. chaxus commented on Aug 10, 2026

    @chaxus
    Member

    @zjhtsgr 你的验证结论是对的——上一版修复确实无效,让你白测了一轮,抱歉。不过根因和你推断的不一样,不在 OnlyOffice SDK,在我这边的修复代码本身。这次已经定位清楚并且在真实 Qt WebEngine 环境里验证过了,展开说一下:

    真正的根因

    x2t 转换出来的 Editor.bin 本身就是一个文本容器,以 DOCY;v5;<长度>;<base64> 开头;而 SDK 对字符串类型的 buf 只做字面签名检查(buf.slice(0,4) === 'DOCY'),不会先做 base64 解码。上一版修复把 bin 整体又 btoa 了一层,buf 变成了 RE9DWT... 开头,SDK 自然认不出来——所以它在所有环境下都是坏的:你的 Qt WebEngine 里表现为 -85 报错,桌面 Chrome 里表现为永远卡在 "Loading document",症状不同、根因相同。

    修复与验证

    分支已更新(8a9114b):改为把 bin 原文按 latin1 逐字节转成字符串发送,保留 DOCY; 签名头。字符串跨 postMessage 依然不会失真,所以你最初报告的 ArrayBuffer 跨 WebView 边界失真问题同样被覆盖。

    这次我没有只跑单测——用 PySide6 6.11.1 + Qt WebEngine 在本地复刻了你的宿主场景做了双向验证:

    • 修复后代码:asc_openDocument 的 buf 前缀为 DOCY;v5;,onDocumentReady 正常触发,文档打开成功;
    • 上一版坏代码:buf 前缀 RE9DWT,触发 onError(就是你看到的 -85),文档打不开。

    复现用的宿主代码也一并提交进了仓库:demo/qt-webengine/(README 里有运行方法),你可以直接拿它和你自己的宿主代码对照。另外 CI 里也加了端到端回归测试(test/e2e/embed-open-buffer.spec.ts),以后这条链路再出问题会直接红。

    麻烦你最后确认一轮

    重新拉 fix/issue-113-embed-buffer-base64 分支构建后测试。如果还有问题,在 sendCommand 处打印 buf.slice(0, 8) 贴上来即可一击定位:

    前缀 含义
    DOCY;v5; 数据正确,问题在别处(贴完整日志我们继续查)
    RE9DWT 还在跑旧代码,确认分支和构建缓存
    UEsDB 原始 docx 没经过 x2t 转换,查你环境里 x2t WASM 是否加载成功

    最后一个建议:你日志里 onAppReady 被调用了 4 次,说明宿主侧把 open 消息发了 4 次(每次都会销毁重建编辑器)。这与 -85 无关,但建议查一下 PySide6 那边是否有重试逻辑,只发一次就够了。

  6. reopened this on Aug 11, 2026
  7. chaxus commented on Aug 15, 2026

    @chaxus
    Member

    已在 v9 版本修复:编辑器底座升级为 OnlyOffice 9.3(旧版对 document:open-buffer 的二进制处理会破坏文件头,导致引擎误判为 pdf/djvu/xps 报 -85)。现在 open-buffer 直接以原始字节走 blob URL 打开,并有真实编辑器 E2E 回归守护(多 sheet 工作簿 open-buffer 打开 + 保存往返)。本次 v9 版本合入 main 部署 edit.chaxus.com 后生效;如更新后仍能复现,请重新打开此 issue。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions