jk's notes
  • OnlyOffice 使用笔记

OnlyOffice 使用笔记

官方文档: https://api.onlyoffice.com/zh/editors/basic

基本概念

是开源的 Office 套件. 提供了, 编辑查看, 与协作功能.

架构模型中 OnlyOffice 需要一个文档服务器来专门处理 Office. 基本架构模型为:

image-20240709103627126

前端需要使用的 JS 库可以在: https://documentserver/web-apps/apps/api/documents/api.js 中找到

其中 documentserver 为安装了 OnlyOffice 的服务器.

安装 OnlyOffice 的链接为: 官网链接.

可以开了使用 Docker 来安装:

docker pull onlyoffice/documentserver

运行使用

docker run -i -t -d -p 8080:80 
  --restart=always 
  -e JWT_SECRET=my_jwt_secret 
  -e JWT_ENABLED=false
  -e ALLOW_PRIVATE_IP_ADDRESS=true
  onlyoffice/documentserver

这里需要注意的是 JWT_SECRET, 在 7.2+ 以后, 会使用随机 JWT, 因此在重启后, 会得到不同的 JWT, 因此启动时需要指定秘钥. 如不使用 JWT, 可以设置 JWT_ENABLED=false

本地测试环境一般会使用 IP 作为访问, 不要使用 localhost, 在容器中, 会使用提供的 url 来请求本地服务器的文件与回调地址. localhost 会导致找不到文件, 使用 IP 为私有 IP, 因此需要配置 ALLOW_PRIVATE_IP_ADDRESS.

另外 OnlyOffice 的默认卷:

  • /var/log/onlyoffice 存放 ONLYOFFICE Docs 日志.
  • /var/www/onlyoffice/Data 存放证书.
  • /var/lib/onlyoffice 作为文件缓存目录.
  • /var/lib/postgresql 数据库.

设置端口映射为 8080, 然后就可以通过 http://localhost:8080/web-apps/apps/api/documents/api.js 来查看代码了:

image-20240709111958529

使用 http://localhost:8080/healthcheck 检查是否可用, 要求返回 true

使用步骤

前期准备 (后端)

需要一个本地的后台应用, 用于维护文档, 以及对文档的处理逻辑 (这里使用 Koa 项目来模拟).

原计划使用 dotnet, 但强类型对 JSON 不友好.

mkdir onlyoffice-back-api && cd onlyoffice-back-api
npm init -y
npm i koa koa-body koa-router koa-static
npm i nodemon

然后编写文档

const Koa = require('koa')
const { koaBody } = require('koa-body')
const Router = require('koa-router')
const serve = require("koa-static")
const path = require('path')

const router = new Router()

router.post('/url-to-callback', koaBody(), ctx => {
  console.log('body', ctx.request.body)
  ctx.body = {
    error: 0,
    status: 200,
    message: 'OK',
    success: true
  }
})
 
const app = new Koa()
app.use(serve(path.resolve(__dirname, 'wwwroot')))

app.use(router.routes())

const ser = app.listen(8081)

console.log(`开始监听: `, ser.address())

同时准备 docx 与 xlsx 文件:

image-20240709171259834

前端步骤(基本用法)

  1. 引入 js 文件, 该文件在 OnlyOffice 服务器上.
  2. 准备站位标签, 设置 id="placeholder".
  3. 准备配置项.
  4. 编写 JS 代码, 获得 docEditor

详细步骤:

<div id="placeholder"></div>
<script type="text/javascript" src="https://localhost:8080/web-apps/apps/api/documents/api.js"></script>

需要添加相关样式

const config = {
    "document": {
        "fileType": "docx",
        "key": "Khirz6zTPdfd7",
        "title": "Example Document Title.docx",
        "url": "http://localhost:8081/test.docx"
    },
    "documentType": "word",
    "editorConfig": {
        "callbackUrl": "http://localhost:8081/url-to-callback"
    }
};
const docEditor = new DocsAPI.DocEditor("placeholder", config);

如果是处理 XLSX 文件, 配置项修改为

const config = {
    "document": {
        "fileType": "xlsx",
        "key": "Khirz6zTPdfd7",
        "title": "Example",
        "url": "http://localhost:8081/test.xlsx"
    },
    "documentType": "cell",
    "editorConfig": {
        "callbackUrl": "http://localhost:8081/url-to-callback"
    }
};

运行后即可访问到文档

image-20240709171425378

或者是

image-20240709171546106

后端应用模型

后端需要提供至少三个接口

  1. 上传文件, 似乎没有看到创建文件的接口. 采用上传的方式添加文件.
  2. 获得文件的接口, 使用该接口访问文档, 并将其放在 document.url 的位置, 给 OnlyOffice 来展示文档.
  3. 回调接口 (POST) 请求, 在文件发生变化时, OnlyOffice 服务会向该回调接口发送请求, 传递必要信息.

使用 Vue 项目作为客户端

步骤:

  1. 安装组件 @onlyoffice/document-editor-vue
  2. 导入组件 import { DocumentEditor } from "@onlyoffice/document-editor-vue"
  3. 配置数据, 可配置的数据参考 Vue API 文档

必须提供的数据有:

  • id 唯一标识.
  • documentServerUrl OnlyOffice 服务地址.
  • config 配置项.

作为一个示例, 使用 vite 构建工具的 vue 模板. 参考代码为:

<script setup lang="ts">
import { DocumentEditor, IConfig } from '@onlyoffice/document-editor-vue'
import { ref } from 'vue';

const config = ref<IConfig>({
  document: {
    fileType: 'xlsx',
    key: 'test123',
    title: '电子表格',
    url: 'http://192.168.1.102:8081/test.xlsx'
  },
  documentType: 'cell',
  editorConfig: {
    callbackUrl: 'http://192.168.1.102:8081/url-to-callback',
    mode: 'edit'
  }
})
</script>

<template>
  <div class="content">
    <DocumentEditor 
      id="docEditor"
      documentServerUrl="http://192.168.1.102:8080"
      :config="config"
    ></DocumentEditor>
  </div>
</template>

<style scoped>
.content {
  width: 80vw;
  height: 80vh;
  border: 1px dashed blue;
}
</style>

它是如何运作的

整个运行模型涉及三方概念:

  1. 浏览器应用 (前端应用), 使用 HTTP 请求 与 DocumentEditor 来与服务端通信 (包括本地服务端, 和 OnlyOffice 服务端).
  2. 本地服务器. 提供文件管理接口, 以及用于 OnlyOffice 回调的接口 (回调响应 { error: 0 } 表示正常).
  3. OnlyOffice 文档服务器. 提供 文档编辑服务, 文档命令服务 (附加 API), 文档转换服务, 文档生成器服务, 以及文档编辑器模块 (前端使用).

1. 打开一个文件

实现流程流程

  1. 用户使用文档管理器 (本地服务提供) 选择需要展示的文件, 获得文件 id 和 url.
  2. 浏览器中的 JavaScript API (OnlyOffice 提供), 获得文件 id 和 url, 来初始化文档编辑器.
  3. 文档编辑器 将文档 id 与 url 发送给文档编辑服务, 来打开文档.
  4. 文档编辑服务 使用 id 与 url 从文档存储服务 下载文档 (下载到了 文档编辑服务 中), 并将其转换为 OpenXML 中间格式.
  5. 准备就绪后, 文档编辑服务将文档返回给浏览器的文档编辑器中.
  6. 文档编辑器显示文档, 并提供编辑功能. 并实时与文档编辑器服务通信.

image-20240711171809091

实现条件

  1. 本地服务文档管理接口提供 文件 id (配置中的 key), 与文件访问的 url (可以是静态 url, 也可以是用接口返回的文件流).
  2. 浏览器使用文档编辑器 (DocumentEditor, OnlyOffice 提供). 配置 id (唯一标识, 必须提供), 文档服务器地址 (OnlyOffice 的地址), 以及 config 配置. config 配置中提供文件的描述, 以及编辑功能的配置.
  3. 非编辑模式下, 不需要本地后端的 callback 接口响应.

image-20240711164937848

官网提供的流程与图逻辑上是没问题的. 但是隐藏了细节.

  • 文档编辑器使用 iframe 迁入到当前页面中, 而 iframe 由 OnlyOffice 提供.
  • 完成初始化后, 文档编辑器 (浏览器) 与 OnlyOffice 的文档编辑服务创建 ws 信道. 实时进行通信. 而该信道由内部的 Node 服务来处理.
  • 加载文档, 编辑文档等交互操作均通过 ws 信道与 OnlyOffice 服务器进行通信.
  • 保存等行为, 也是将信息通过 ws 传递给 OnlyOffice 服务来处理. 在其内部时通过调用相关 API 来实现的. 例如打开文档传递了 Cmd 信息:

image-20240711165659121

2. 保存文件

官方文档描述很清晰

image-20240711171825483

  1. 用户在 文档编辑器 中编辑文档.
  2. 文档编辑器 将变更发送 (实时, 使用 ws 信道) 给 文档编辑服务.
  3. 用户关闭 文档编辑器. 默认情况, 除非配置 强制保存.
  4. 文档编辑服务 识别到文档工作结束, 将所有变更收集到一个文档中.
  5. 文档编辑服务 使用 文档编辑器 中配置的 callback 回调 url 来通知本地服务器. 并返回修改后的文档 url.
  6. 本地服务器 再通过更新文件的 url 下载文件, 并将文件存储于 文件存储服务 中.

补充: 多人编辑文档时, callbackUrl 从最后一个加入的用户开始使用的. (有待验证).

3. 共同编辑

image-20240711175503685

  1. 用户1 和 用户2 在 文档编辑器 中打开同一个文档, 使用 key 来进行唯一标识, 即使同一个 url, key 不同也视为不同的文档.
  2. 假定 用户1 更改了文档 (待验证这个更改是否为实时).
  3. 文档编辑器 将 用户1 的更新发送到 文档编辑服务.
  4. 文档编辑服务 将 用户1 的更新发送给 用户2 的 文档编辑器.
  5. 然后 用户2 即可看到更新.

补充说明

必须使用同一个 key 才表示同一个文件. key 只能使用 0-9, a-z, A-Z, -._=. key 最大长度为128个 字符.

一旦发送保存请求 (status 的值为 2), 并且本地回调服务响应成功 ({ error: 0 }). 则该 key 不再允许编辑 (会提示文档已被修改需要重新加载), 但是可以从缓存中查看 (如果存在).

如果用户在编辑完成之前保存文档 (status 的值为 6), 则不能更改 key (什么意思???), 否则共同编辑停止.

有待验证上面这句话, 不允许修改 key 是啥含义? 事实上, 更新 key 就意味着新的文档. 在 Vue 中可以使用绑定, 自动更新配置; 传统方法中, 可以使用 docEditor 实例来通过方法来更新 配置 的数据.

还有一个需要验证, 关闭文档编辑器怎么实现? 已验证, 关闭浏览器就会触发保存 (status 为 2).

一些结论

  • 当用户采用同一个 key 进入 文档编辑器 时, 不会向本地后端发起文件请求, 而是使用 ws 信道直接获取文件.
  • 事实上, 进入 文档编辑器 后, 文档编辑服务 会缓存所请求的文档, 但凡再次请求该文件 (用 key 标识), 都不会向本地服务发起请求. 文档编辑器 的配置中, key 是主导, url 只是在需要时, 用于请求的属性.
Last Updated:
Contributors: jk