使用 ONLYOFFICE 转换 API 构建在线文档转换器

news2024/10/3 8:18:21

文档转换是非常常用、非常有价值的功能,可以帮助我们处理多种文档类型。ONLYOFFICE 编辑器可以轻松地将文档转换为多种格式。在这篇博文中,我们会向您展示,如何构建在 ONLYOFFICE 转换 API 上运行的在线转换器。

关于 ONLYOFFICE 转换 API

使用文档转换服务,您可就各种类型的 Office 文档做转换:文本、表格、幻灯片、表单、PDF 和电子书。它帮助您基于文档和表格创建 PDF,将教科书转换为电子书,将演示文稿转换为图片文件,等等。ONLYOFFICE 支持 50 多种文件类型。

操作方法

我们的转换 API 通过“文档转换服务”运行。它是 ONLYOFFICE 文档服务器的一部分,支持我们将各种文档文件转换为合适的格式。

转换要分几个步骤进行:

  1. 用户选择一个要上传到“文档管理器”的文件。
  2. “文档管理器”将选定的文件上传到“文档存储服务”。
  3. “文档存储服务”通过使用“转化 API”将上传的文件发送到“文档转换服务”。
  4. “文档转换服务”将选定的文件转换为目标格式。
  5. “文档存储服务”下载转换后的文档文件。

“文档管理器”和“文档存储服务”是客户端和服务器端的工具,方便选择和存储文档供进一步转换。不过,我们的 web 应用会处理这些任务,这得益于我们正在构建的自定义转换器。

前提条件

我们的转换器基于 NodeJS。因此,对于这个项目,我们需要如下条件:

  • ONLYOFFICE 文档服务器
  • 安装了如下软件包的 NodeJS 应用:
    – Express
    – Axios
    – Jsonwebtoken

我们会使用 Axios 包向 ONLYOFFICE 文档服务器发送一个 post 请求,并使用 Jsonwebtoken 包签署一个 JWT 令牌。从版本 7.2 开始,JWT 认证默认处于启用状态。

或者,您还可以通过另一个选项,在 JWT 认证停用的情况下运行 ONLYOFFICE 文档服务器镜像。为此,请在终端执行如下命令:

sudo docker run -i -t -d -p 80:80 -e JWT_ENABLED=false onlyoffice/documentserver

我们的转换器向 ONLYOFFICE 文档服务器发送的“post 请求”如下:

{
        "async": true,
        "filetype": fileType,
        "key": key, 
        "outputtype": outputType,
        "title": `Converted Document.${outputType}`,
        "url": link      
    }
  • 在“accept”参数中,我们指定要接收 JSON 格式的响应。
  • “async”参数指示该请求是异步请求。
  • “fileType”参数指定我们要转换的原始文件的类型。
  • “key”参数指定当前文件的唯一标识符 (UID)。
  • “outputType”参数指定转换后的文件的格式。
  • “title”参数包含转换后的文档的名称。
  • “url”参数包含指向我们要转换的文件的链接。

“fileType”、“outputType”和“url”参数的值是从我们应用的客户端获取,存储在变量中。“key”参数的值也是随机生成,存储在变量中。

项目设置

将所需的包安装好后,我们前往“app.js”文件,将它们与“bodyParser”一起初始化,以处理“post 请求”数据。我们还创建了一个公开文件夹和一个视图引擎:

const express = require('express');
const app = express();
const axios = require('axios'); 
const jwt = require('jsonwebtoken');
 
 
app.use(express.urlencoded({extended: true}));
app.use(express.json());
app.use(express.static("public"));
app.set('view engine', 'ejs');

然后我们添加路由。我们的应用会包含一个“get”路由和一个“post”路由。我们可以使用它们来获取输入数据,并将数据传递到 ONLYOFFICE 文档服务器的“post 请求”中:

app.get ('/', function (reg, response){ 
}
 
app.post ('/converter', function(req, response){
}

客户端

现在我们花点时间,看看转换器的客户端。就是在这里,我们要输入所有所需数据:

客户端包括两个 EJS 页面:

  • homepage.ejs:我们在这里提取“post 请求”所需的所有值。
  • converter.ejs:我们在这里下载转换后的文件。

我们来详细看看“homepage.ejs”。这里我们创建了一个表单,将数据发送到“post”路由。首先,我们获得一个原始文件的URL。我们将把其存储在服务器端的“link”变量中:

<h1 class="h3 mb-3 font-weight-normal">Convert your OOXML files here!</h1>
        <input type="text"  class="form-control" id="inputEmail" placeholder="Paste a link to the file" name="link" onchange="activateBox()">

然后我们在组合框中选一个原始文件的类型。之后,我们提取这个值,并将其存储在“inputType”变量中:

<select class="form-control" id="inputType" input type="text" disabled="true" name="inputType" onchange="comboBox()">
          <option value="" selected>Input File Type</option>
          <option value="docx">docx</option>
          <option value="txt">txt</option>
          <option value="pdf">pdf</option>
          <option value="rtf">rtf</option>
          <option value="xml">xml</option>
          <option value="csv">csv</option>
          <option value="xlsx">xlsx</option>
          <option value="xls">xls</option>
          <option value="ppt">ppt</option>
          <option value="pptx">pptx</option>
</select>

然后,我们选择所需的文件类型。这个值会被储存在服务器端的“outputType”变量中:

<select class="form-control" id="outputType" input type="text" disabled="true" name="outputType" onchange="activateButton()">
      <option value="" disabled selected hidden>Output File Type</option>
    </select>

我们用一个按钮将所有数据发送到“转换器”post 路由:

<div class="button">
      <button type="submit" id="download" disabled="true" class="btn btn-lg btn-primary btn-block">Convert</button>
    </div>
    </form>

构建转换器

提取的数据会在我们应用的服务器端进行解析。现在,我们前往“app.js”文件去获取:

app.post ('/converter', function(req, response){
    let link = req.body.link;
    let outputType = req.body.outputType;
    let fileType = req.body.inputType;
 
});

现在我们看看第二个组合框,它将“outputType”值发送到“post”路由:

  <select class="form-control" id="outputType" input type="text" disabled="true" name="outputType" onchange="activateButton()">
      <option value="" disabled selected hidden>Output File Type</option>
    </select>

“outputType”变量包含在对服务器的“post 请求”中。它指定转换后的文件的格式。我们来看看支持我们与页面元素互动的 JavaScript 代码,并将动态列表并入我们的用户界面。

“文档转换服务”是一个非常强大的工具,能够转换各种类型的文件。所以我们的目标是利用一个动态列表,让我们为转换后的文件选择一种格式。这个列表会显示针对特定类型的原始文件的所有可用选项。

为此,我们创建一个 JSON 文件,按照每个特定的类型来存储数值:

请注意!在示范中,我们只列出了最常用的 OOXML 格式。如要了解所有受支持的转换选项,请访问我们的文档页面。
然后我们添加一个函数来生成这个动态列表:

function comboBox () {
     let type = document.querySelector("#inputType").value;
     let listDropDown = document.querySelector("#outputType");
     fetch("formats.json")
    .then(function(response){
      return response.json();
    })
    .then(function(data){
     let options = data[type];
     let out = "";
     out += `<option value="">Output File Type</option>`;
     Object.values(options).map(function(format){
        out += '<option value=' + format + '>' + format + '</option>';
      });
     listDropDown.innerHTML = out;
     listDropDown.disabled = false;
               });  
    };
        };

首先,这个函数获取“inputType”组合框的值,我们在这里选择原始文件的格式。我们把它分配给“type”变量,以便在后面使用这个值。然后我们发出一个 AJAX 请求来加载 JSON 数据。之后,我们使用“type”变量的值作为索引,迭代加载的数据,将其值插入下拉列表的选项中。

现在,我们每次选择原始文件的类型时,脚本就会执行,并按照原始文件格式向我们显示可用的转换选项。
而在我们得到所有需要的数据后,点击“转换”按钮即可将其发送到转换器路由。

但实际不是这样。为了让我们的应用更具互动性,我们会添加函数,以正确的顺序激活组合框和按钮元素:

 function activateBox() {
      $("#inputType").prop('disabled', false)
    };
    
    function activateButton() {
      $("#download").prop('disabled', false)
      $("#outputTypeForm").hide();
    };

完整的 JavaScript 代码如下:

     function comboBox () {
     let type = document.querySelector("#inputType").value;
     let listDropDown = document.querySelector("#outputType");
     fetch("formats.json")
    .then(function(response){
      return response.json();
    })
    .then(function(data){
     let options = data[type];
     let out = "";
     out += `<option value="">Output File Type</option>`;
     Object.values(options).map(function(format){
        out += '<option value=' + format + '>' + format + '</option>';
      });
     listDropDown.innerHTML = out;
     listDropDown.disabled = false;
               });  
    };
    function activateBox() {
      $("#inputType").prop('disabled', false)
    };
    
    function activateButton() {
      $("#download").prop('disabled', false)
      $("#outputTypeForm").hide();
    };
        }

我们来看看服务器端的状态:

app.post ('/converter', function(req, response){
    let link = req.body.link;
    let outputType = req.body.outputType;
    let fileType = req.body.inputType;
    let key =  function () {
        var key = '';
        var str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + 
                'abcdefghijklmnopqrstuvwxyz0123456789';
          
        for (let i = 1; i <= 12; i++) {
            var char = Math.floor(Math.random()
                        * str.length + 1);
              
            key += str.charAt(char);
        }
          
        return key;
    };
    const payload =  { 
        "async": true,
        "filetype": fileType,
        "key": key, 
        "outputtype": outputType,
        "title": `Converted Document.${outputType}`,
        "url": link       
    }
    let token = jwt.sign(payload, secret, options);
    
    axios.post( 
        'http://127.0.0.1:83/ConvertService.ashx',
        { 
           "token": token
        }) 
        .then((res) => response.render('converter.ejs', {
            link: res.data.fileUrl
        })) 
});

在“converter”路由中,我们生成了针对 ONLYOFFICE 文档服务器的 post 请求,并将其存储在“payload”变量中。我们使用了“fileType”、“outputType”和“link”变量,我们提取的数据也是存储在这些变量中。然而,我们还有一个“key”变量,包含当前文档的唯一标识符。所以我们在上面添加了一个小函数来将其生成:

    let key =  function () {
        var key = '';
        var str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + 
                'abcdefghijklmnopqrstuvwxyz0123456789';
          
        for (let i = 1; i <= 12; i++) {
            var char = Math.floor(Math.random()
                        * str.length + 1);
              
            key += str.charAt(char)
        }   
        return key;
    };

现在,所有关于请求的必要的值都齐备了,我们用 jwt.sign 把它们封装在一个令牌中:

  let token = jwt.sign(payload, secret, options);

“jwt.sign”方法需要三个参数:

  • Payload:包括成功转换所需的所有参数。
  • Header:包含加密算法和过期时间范围相关信息。我们将这些参数封装在选项变量中。
  • Secret:代表 ONLYOFFICE 文档服务器生成的密钥。您可以在 local.json 文件中找到这个密钥,或者通过在终端执行如下命令:
sudo docker exec <dockerID> /var/www/onlyoffice/documentserver/npm/json -f /etc/onlyoffice/documentserver/local.json 'services.CoAuthoring.secret.session.string'

在签署了令牌之后,我们再使用一个“axios post request”将其发送到服务器。然后我们呈现“converter.ejs”页面,该页面从 ONLYOFFICE 文档服务器接收响应:

 axios.post( 
        'http://127.0.0.1:83/ConvertService.ashx',
        { 
           "token": token
        }) 
        .then((res) => response.render('converter.ejs', {
            link: res.data.fileUrl
        }))

这是 JSON 格式响应的样本:

{     "endConvert": true,     "fileType": "docx",     "fileUrl": "https://documentserver/url-to-converted-document.pdf",     "percent": 100 }

这里需要“fileUrl”元素,是指向转换后的文件的链接。所以我们要获取它,并将其发送到“converter.ejs”页面:

.then((res) => response.render('converter.ejs', {
            link: res.data.fileUrl
        })) 
});

在该页面,我们创建两个按钮。“返回”按钮可让我们回到 homepage.ejs 页面;“下载”按钮则打开我们发送到该页面的链接,并下载转换后的文件:

请注意!如需详细了解 JWT,请访问我们的文档页面。

服务器端完整代码如下:

const express = require('express');
const app = express();
const axios = require('axios'); 
const jwt = require('jsonwebtoken');
const options = {algorithm: "HS256", expiresIn: "5m"};
const secret = "k1gWQdmDX6ZGiWw5r3g2";
app.use(express.urlencoded({extended: true}));
app.use(express.json());
app.use(express.static("public"));
app.set('view engine', 'ejs');
app.get ('/', function (reg, response){ 
    response.render('homepage.ejs', {
    })
});
app.post ('/converter', function(req, response){
    let link = req.body.link;
    let outputType = req.body.outputType;
    let fileType = req.body.inputType;
    let key =  function () {
        var key = '';
        var str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + 
                'abcdefghijklmnopqrstuvwxyz0123456789';
          
        for (let i = 1; i <= 12; i++) {
            var char = Math.floor(Math.random()
                        * str.length + 1);
              
            key += str.charAt(char);
        }
          
        return key;
    };
    const payload =  { 
        "async": true,
        "filetype": fileType,
        "key": key, 
        "outputtype": outputType,
        "title": `Converted Document.${outputType}`,
        "url": link       
    }
    let token = jwt.sign(payload, secret, options);
    
    axios.post( 
        'http://127.0.0.1:83/ConvertService.ashx',
        { 
           "token": token
        }) 
        .then((res) => response.render('converter.ejs', {
            link: res.data.fileUrl
        })) 
});
app.listen(3000,() => console.log('the server is up and running'));

现在,我们来运行转换器,了解如何使用!

ONLYOFFICE 解决方案的功能非常丰富。这些解决方案为用户和开发者提供独特体验,让他们能够以多种方式操作 ooXML 文档。我们希望您觉得如上提到的信息很有用,并将其应用在您未来的项目中。欢迎您发表评论、提出问题或与我们分享您的想法,我们乐意接受建议、展开合作。祝您的探索一切顺利!

相关链接

ONLYOFFICE 文档服务器

转换 API 文档

签名文档

详细了解 JWT

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/347685.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

傻白探索Chiplet,Design Space Exploration for Chiplet-Assembly-Based Processors(十三)

阅读了Design Space Exploration for Chiplet-Assembly-Based Processors这篇论文&#xff0c;是关于chiplet设计空间探索的&#xff0c;个人感觉核心贡献有两个&#xff1a;1.提出使用整数线性规划算法进行Chiplet的选择&#xff1b;2.基于RE和NRE提出了一个cost模型&#xff…

Map和Set(Java详解)

在开始详解之前&#xff0c;先来看看集合的框架&#xff1a; 可以看到Set实现了Collection接口&#xff0c;而Map又是一个单独存在的接口。 而最下面又分别各有两个类&#xff0c;分别是TreeSet&#xff08;Map&#xff09;和 HashSet&#xff08;Map&#xff09;。 TreeSet&…

CSS---动态向下的循环箭头动画效果

介绍 在移动端的页面中&#xff0c;经常有翻页的提示效果&#xff0c;经常使用向下的箭头动画来提示&#xff1b;一般效果如下所示&#xff1a; 使用到的图片 使用到的图片&#xff0c;就是一个向下的箭头&#xff1b;这里可以下载我的图片使用&#xff1b; 或者也可以使用…

92.【SpringCloud NetFilx】

SpringCloud(一)、这个阶段该如何学习?1.微服务介绍2.面试常见问题(二)、微服务概述1.什么是微服务?2. 微服务与微服务架构(1).微服务(2).微服务架构⭐(3). 微服务优缺点(4). 微服务技术栈有那些&#xff1f;(5). 为什么选择SpringCloud作为微服务架构(三)、SpringCloud入门概…

Python 之 Matplotlib 第一个绘图程序和基本方法

文章目录一、第一个 Matplotlib 绘图程序1. Matplotlib 绘图的基本步骤二、Matplotlib 的基本方法1. 图表名称 plt.title()2. x 轴和 y 轴名称3. 设置 x 轴和 y 轴的刻度4. 显示图表 show()5. 图例 legend()6. 图例的图例位置设置7. 显示每条数据的值 x,y 值的位置一、第一个 M…

LeetCode 61. 旋转链表

原题链接 难度&#xff1a;middle\color{orange}{middle}middle 题目描述 给你一个链表的头节点 headheadhead &#xff0c;旋转链表&#xff0c;将链表每个节点向右移动 kkk 个位置。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], k 2 输出&#xff1a;[4,5,1…

wafw00f源码及流量特征分析

wafw00f介绍 这不是本次的重点&#xff0c;相关介绍及使用方法相信大家已经了解&#xff0c;所以此处就直接引用其开发者对该工具的介绍。 To do its magic, WAFW00F does the following: Sends a normal HTTP request and analyses the response; this identifies a number o…

(考研湖科大教书匠计算机网络)第四章网络层-第三节3、4:划分子网的IPv4地址和无分类IP地址

获取pdf&#xff1a;密码7281专栏目录首页&#xff1a;【专栏必读】考研湖科大教书匠计算机网络笔记导航 文章目录一&#xff1a;划分子网的IPv4地址&#xff08;1&#xff09;划分子网思想&#xff08;2&#xff09;子网掩码A&#xff1a;概述B&#xff1a;例子C&#xff1a;默…

Django 模型继承问题

文章目录Django 模型继承问题继承出现的情况Meta 和多表继承Meta 和多表继承继承与反向关系指定父类连接字段代理模型QuerySet 仍会返回请求的模型基类约束代理模型管理器代理继承和未托管的模型间的区别多重继承不能用字段名 "hiding"在一个包中管理模型Django 模型…

linux安装极狐gitlab

1. 官网寻找安装方式 不管我们使用任何软件&#xff0c;最靠谱的方式就是查看官方文档。gitlab提供了相应的安装文档&#xff0c;并且有对应的中文文档。地址如下&#xff1a; https://gitlab.cn/install/ 我在这里以CentOS作为安装示例&#xff0c;大家可根据自己的需要选择…

LabVIEW中ActiveX控件、ActiveX服务器和类型库注册

LabVIEW中ActiveX控件、ActiveX服务器和类型库注册如何在计算机上手动注册ActiveX控件&#xff08;.ocx &#xff09;、ActiveX服务器&#xff08;.DLL和.EXE&#xff09;以及类型库&#xff08;.TLB &#xff09;&#xff1f;在LabVIEW中打开ActiveX控件或类的引用时&#xff…

XCP实战系列介绍12-基于Vector_Davinci工具的XCP配置介绍(一)

本文框架 1.概述2. EcuC配置2.1 Pdu添加步骤2.2 配置项说明3. Can 模块配置4. CanIf 模块配置4.1 接收帧的Hardware Receive Object配置4.2 接收帧和发送帧的Pdu配置1.概述 在文章《看了就会的XCP协议介绍》中详细介绍了XCP的协议,在《XCP实战系列介绍01-测量与标定底层逻辑》…

ELK分布式日志收集快速入门-(二)kafka进阶-快速安装可视化管理界面-(单节点部署)

目录安装前准备安装中安装成功安装前准备 安装kafka-参考博客 (10条消息) ELK分布式日志收集快速入门-&#xff08;一&#xff09;-kafka单体篇_康世行的博客-CSDN博客 安装zk 参考博客 (10条消息) 快速搭建-分布式远程调用框架搭建-dubbozookperspringboot demo 演示_康世行的…

Python编程 动态爱心

作者简介&#xff1a;一名在校计算机学生、每天分享Python的学习经验、和学习笔记。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​​ 目录 前言 一.所用库 1.random简介 2.math 简介 3.tkinter库的简介 二.实际图 三.…

OKR之剑·实战篇06:OKR致胜法宝-氛围业绩双轮驱动(下)

作者&#xff1a;vivo 互联网平台产品研发团队 本文是《OKR 之剑》系列之实战第 6 篇—— 本文介绍团队营造氛围的方法与实践、在业绩方面的探索与输出&#xff0c;在两方面分别总结了一些经验分享给大家。 一、我们营造氛围的方法与实践 先说说氛围。组织氛围的提出者库尔…

10分钟学会数据库压力测试,你敢信?

目录 前言 查看数据库版本 下载驱动&#xff1a; 菜单路径 配置 Variable Name Bound to Pool模块配置 Connection pool configuration模块配置 Database Connection Configuration模块配置 菜单路径 Variable Name Bound to Pool 脚本结构 脚本&#xff08;执行查询…

2.3 IS-IS认证

2.2.3 实验三:IS-IS认证 1. 实验目的  实现IS-IS接口认证 实现IS-IS区域认证实验IS-IS路由域认证2. 实验拓扑 IS-IS认证的实验拓扑如图2-6 图2-6:IS-IS认证 3. 实验步骤 配置IP地址(此处略…

让ChatGPT做当年的高考现代文阅读

最近ChatGPT火出天际&#xff0c;我突发奇想&#xff0c;如果用ChatGPT来做高考现代文阅读会怎样。 于是找到了当年非常火的一篇文章&#xff0c;叫《一种美味》&#xff0c;这个名字大家可能不太熟&#xff0c;但是提到其中一句话&#xff0c;你可能立马就想起来了。 「眼里…

一些NLP术语

一些NLP术语pre-training&#xff08;预训练&#xff09;fine-tuning&#xff08;微调&#xff09;下游任务Few-shot Learning&#xff08;少样本学习&#xff09;Prompt&#xff1f;&#xff08;自然语言提示信息&#xff09;二级标题三级标题pre-training&#xff08;预训练&…

Redis第一讲

目录 一、Redis01 1.1 NoSql 1.1.1 NoSql介绍 1.1.2 NoSql起源 1.1.3 NoSql的使用 1.2 常见NoSql数据库介绍 1.3 Redis简介 1.3.1 Redis介绍 1.3.2 Redis数据结构的多样性 1.3.3 Redis应用场景 1.4 Redis安装、配置以及使用 1.4.1 Redis安装的两种方式 1.4.2 Redi…