guide协作导入和导出

# 概述

在具有多个用户的活动协作会话中保存文档数据的过程可能具有挑战性。使用 自动保存插件 的简单实现存在一些缺点。另一种初始化和保存协作数据的办法可以解决大多数问题。

基于 REST API 的导入和导出功能改进了同步保存在数据库中的文档数据的过程。使用此功能时,保存当前文档数据的责任将从用户转移到您的服务器。

# 导入和导出端点

此功能利用了 REST API 中提供的两种方法

  • 导入文档 – 使用此端点设置初始内容并创建新的协作会话。如果使用给定的 documentId 已经存在协作会话,则此端点将无法工作。
  • 导出文档 – 使用此端点从活动协作会话中获取内容。在响应中,您将获得编辑器中的纯 HTML 或 Markdown 输出(取决于编辑器配置),就像您在客户端调用 editor.getData() 一样。如果在编辑器中使用相应的插件,导出的文档数据可能包含注释和/或建议标记。要导出不包含这些标记的文档,请使用 文档导入和导出 功能。

请遵循本指南了解如何正确设置和使用此功能。

# 先决条件

要使用导入和导出功能,需要将带有其配置的编辑器上传到 CKEditor 云服务服务器。云服务使用您的编辑器在导出期间生成正确的输出,并在导入期间验证输入。由于采用了这种方法,您用于生成一些自定义数据的自定义插件也将正常工作。

在开始使用此功能之前,需要执行两个步骤

  1. 将您的编辑器捆绑包(包含编辑器配置)上传到 CKEditor 云服务服务器。有关更多信息,请参考 编辑器捆绑包 指南。
  2. 在编辑器配置中设置所需的 bundleVersion 属性。有关更多详细信息,请参考编辑器捆绑包文档中的 编辑器配置 部分。

也可以使用 use_inital_data 参数,通过您的数据初始化新的协作会话,而无需上传编辑器捆绑包。请记住,这仅在导入文档时有效。导出功能始终需要上传的编辑器捆绑包。有关更多详细信息,请参考 REST API 文档

# 用法

# 启动协作会话

以下是如何使用保存在数据库中的内容成功初始化编辑会话的推荐流程

  1. 您应用程序中希望打开文档的用户向您的服务器发送 channelId(新的或已存在的)。
  2. 您的服务器与 CKEditor 协作服务器通信,并使用 GET /collaborations/{document_id}/exists REST API 端点验证会话是否已存在。
  3. 您的服务器从数据库中获取文档数据。如果协作会话已经存在,则应跳过此步骤。
  4. 您的服务器通过 POST /collaborations REST API 端点初始化协作会话。如果协作会话已经存在,则应跳过此步骤。
  5. 您的服务器向用户发出信号,表示会话已准备好连接。
  6. 编辑器初始化用户并将其连接到协作会话。

The workflow of initializing collaboration session with Import REST API.

如果协作会话尚不存在,并且您允许用户连接到 CKEditor 协作服务器,则将使用编辑器配置中的 initialData 初始化协作会话。这可用于初始化新的空文档或使用一些预定义模板启动新文档。

# 保存文档数据

根据您的用例,您可以选择以下一种或多种解决方案,将协作会话中的内容保存到您自己的数据库中。

# collaboration.document.exported 网络钩子

我们建议使用 collaboration.document.exported 网络钩子保存文档数据。当协作会话被移除时,此网络钩子会被发出,并且已经包含会话的内容。这确保了保存的内容包括用户在文档编辑期间所做的所有更改,并且您会收到文档的最新版本。

以下是使用此网络钩子的推荐流程

  1. 协作会话结束。您可以等待它在最后一个用户断开连接后自动结束 24 小时,也可以使用 DELETE /collaborations/{document_id} REST API 端点触发它。
  2. CKEditor 协作服务器发出 collaboration.document.exported 网络钩子,其中包含文档的内容和 channelId 属性。
  3. 收到数据后,将其存储在您的数据库中。

The workflow of saving data returned by the collaboration.document.exported webhook.

我们强烈建议使用这种保存协作会话内容的方法,即使您实现了其他解决方案,也要确保编辑的协作会话与存储在您数据库中的数据之间的一致性。

# collaboration.document.update.exported 网络钩子

上面使用 collaboration.document.exported 网络钩子的解决方案确保在协作会话结束时保存最新的内容版本。如果您需要频繁访问活动协作会话中正在编辑的内容的当前版本,您还可以使用 collaboration.document.update.exported 网络钩子。此网络钩子会在活动编辑会话期间以及最后一个用户从协作会话断开连接后定期发出。

以下是使用此网络钩子的推荐流程

  1. 网络钩子由以下触发
    • 用户添加操作(每 10 分钟一次),
    • 用户添加 5000 个操作,或
    • 最后一个用户从协作会话断开连接。
  2. collaboration.document.update.exported 网络钩子(包含文档内容和 channelId 属性)从 CKEditor 协作服务器发出。
  3. 收到数据后,您的服务器将其存储在您的数据库中。

The workflow of saving data returned by the collaboration.document.update.exported webhook.

# 按需导出

如果为 collaboration.document.exportedcollaboration.document.update.exported 网络钩子定义的触发器不符合您的用例,并且您希望创建自定义触发器以获取协作数据,您可以发送 GET /collaborations/{document_id} 请求到 CKEditor 协作服务器,以接收活动协作会话的内容。

以下是使用按需导出的推荐流程

  1. 您应用程序的某些部分或用户操作向您的服务器发送包含 channelId 属性的请求。
  2. 您的服务器向 CKEditor 协作服务器发送 GET /collaborations/{document_id} 请求,以获取协作会话的内容。
  3. 收到数据后,您的服务器将其存储在您的数据库中。

The workflow of triggering export with a custom event.

# REST API 用法

成功将编辑器包上传至 CKEditor 云服务后,您可以开始使用导入和导出功能。每个向云服务 REST API 发出的请求都需要包含以下头部信息:

  • X-CS-Timestamp - 此头部信息的数值将用于生成和验证签名。确保为每个请求使用唯一的数值,以保证生成的签名也保持唯一。此数值需要为数字。当前的 Unix 时间戳就是一个很好的例子。
  • X-CS-Signature - 此头部信息的数值使用 SHA-256 算法生成,并使用 API 密钥 进行签名。CKEditor 云服务也会为每个请求生成签名,并且仅接受具有正确签名的请求。有关详细信息,请参考 请求签名指南

您可以查看 Node.js 和 Express.js 中使用此机制的应用程序示例,或参考本指南了解更多关于该功能使用方法的详细信息。

您也可以查看 CKEditor 云服务示例库,其中包含更多示例。

# 导入示例

导入文档意味着使用之前保存的文档数据创建一个新的协作会话。它基于从您的服务器向 CKEditor 云服务发送请求,请求使用 POST /collaborations REST API 方法,并将所需数据包含在请求主体中。

{
  "document_id": "your_document_id",
  "bundle_version": "your_editor_id",
  "data": "<p>document_content</p>"
}

此时,CKEditor 云服务将使用之前上传的具有指定 bundle_version 的编辑器包,将请求中发送的文档 data 转换为指定的格式,并为 document_id 创建一个活动的协作会话。

完成此操作后,用户可以连接到新创建的协作会话,并继续在已加载的文档上进行操作。

在处理协作数据时,您会发现更多有用的云服务 REST API 方法:

  • 文档是否存在 - 使用此 API 端点检查是否已存在具有指定 documentId 的活动协作会话。请记住,只有在没有活动协作会话的情况下,导入才会成功。您可以在导入数据之前使用此方法进行检查。
  • 清除文档 - 使用此 API 端点删除活动协作会话。没有连接用户的协作会话将在 24 小时后被删除。但如果需要立即删除,可以使用此 API 方法手动删除。

在导入具有 多根编辑器构建 的文档时,data 字段应包含一个字符串化的 JSON 结构,其中键是根名称,值是特定根的 HTML 内容。

本示例使用 node.js 和 npm。确保在执行以下步骤之前已安装这些工具。此代码段假设您已经按照 先决条件 部分中的步骤进行操作。

  1. 运行以下命令:
mkdir cs-import-example && cd cs-import-example
npm init -y && npm i axios
  1. cs-import-example 文件夹中创建一个名为 import.js 的新文件,并添加以下内容:
const crypto = require( 'crypto' );
const axios = require( 'axios' );

// Update with your credentials and application endpoint
const environmentId = 'txQ9sTfqmXUyWU5LmDbr';
const apiSecret = '4zZBCQoPfRZ7Rr7TEnGAuRsGgbfF58Eg0PA8xcLD2kvPhjGjy4VGgB8k0hXn';
const applicationEndpoint = 'https://33333.cke-cs.com';
const apiEndpoint = `${ applicationEndpoint }/api/v5/${ environmentId }/collaborations/`;

const body = {
    document_id: "document-1", // Set document_id of created collaboration session
    bundle_version: "bundleversion-1", // Use bundle_version from uploaded editor bundle
    data: "<p>Lorem Ipsum is <b>simply dummy</b> text of the printing and typesetting industry.</p>"
};

const CSTimestamp = Date.now();
const config = {
    headers: {
        'X-CS-Timestamp': CSTimestamp,
        'X-CS-Signature': generateSignature( apiSecret, 'POST', apiEndpoint, CSTimestamp, body )
    },
};

axios.post( apiEndpoint, body, config )
    .then( response => {
        console.log ( response.status );
    } ).catch( error => {
        console.log( error.message );
        console.log( error.response.data );
    } );

function generateSignature( apiSecret, method, uri, timestamp, body ) {
    const url = new URL( uri );
    const path = url.pathname + url.search;
    const hmac = crypto.createHmac( 'SHA256', apiSecret );

    hmac.update( `${ method.toUpperCase() }${ path }${ timestamp }` );

    if ( body ) {
        hmac.update( Buffer.from( JSON.stringify( body ) ) );
    };

    return hmac.digest( 'hex' );
}
  1. 在代码段中更新您的凭据、document_idbundle_version 的值。

  2. 使用 node import.js 命令运行导入操作。

如果成功响应并返回状态代码 204,则可以使用代码段中设置的相同 document_id 打开编辑器以查看导入的内容。您也可以使用导出方法检查内容。

# 导出示例

导出文档意味着从活动协作会话中获取文档的当前数据。它基于从您的服务器向 CKEditor 云服务发送请求,请求使用 GET /collaborations/{document_id} REST API 方法。

此时,CKEditor 云服务将使用之前加载的编辑器包,将活动协作会话转换为配置的输出格式(HTML、Markdown、文本等),您的服务器将在响应请求时接收这些数据。您的服务器应将接收到的文档数据保存在数据库中。

建议在所有用户断开与文档的连接后至少执行一次此操作。

您可以使用 GET /collaborations/{document_id}/users REST API 方法来获取有关连接到协作会话的用户的信息。或者,您可以使用 用户断开连接 webhook 事件。

对于 多根编辑器构建,导出文档的 data 是一个字符串化的 JSON 结构,其中键是根名称,值是特定根的 HTML 内容。

本示例使用 node.js 和 npm。确保在执行以下步骤之前已安装这些工具。此代码段假设您已经按照 先决条件 部分中的步骤进行操作。

  1. 运行以下命令:
mkdir cs-export-example && cd cs-export-example
npm init -y && npm i axios
  1. cs-export-example 文件夹中创建一个名为 export.js 的新文件,并添加以下内容:
const crypto = require( 'crypto' );
const axios = require( 'axios' );

// Update with your credentials and application endpoint
const environmentId = 'txQ9sTfqmXUyWU5LmDbr';
const apiSecret = '4zZBCQoPfRZ7Rr7TEnGAuRsGgbfF58Eg0PA8xcLD2kvPhjGjy4VGgB8k0hXn';
const applicationEndpoint = 'https://33333.cke-cs.com';

const documentId = 'document-1'; // Set document_id of an active collaboration session
const apiEndpoint = `${ applicationEndpoint }/api/v5/${ environmentId }/collaborations/${ documentId }`;

const CSTimestamp = Date.now();
const config = {
    headers: {
        'X-CS-Timestamp': CSTimestamp,
        'X-CS-Signature': generateSignature( apiSecret, 'GET', apiEndpoint, CSTimestamp )
    },
};

axios.get( apiEndpoint, config )
    .then( response => {
        console.log ( response.data );
    } ).catch( error => {
        console.log( error.message );
        console.log( error.response.data );
    } );

function generateSignature( apiSecret, method, uri, timestamp, body ) {
    const url = new URL( uri );
    const path = url.pathname + url.search;
    const hmac = crypto.createHmac( 'SHA256', apiSecret );

    hmac.update( `${ method.toUpperCase() }${ path }${ timestamp }` );

    if ( body ) {
        hmac.update( Buffer.from( JSON.stringify( body ) ) );
    };

    return hmac.digest( 'hex' );
}
  1. 在代码段中更新您的凭据和 documentId 的值。

  2. 使用 node export.js 命令运行导出操作。

您应该在控制台中看到活动协作会话的内容。