美术馆网站建设总体要求,乐清建设公司网站,金坛城乡建设管理网站,捕鱼网站建设私有 Word 文件在线预览方案#xff08;.doc/.docx 转 PDF#xff09;
前言
由于 .doc 和 .docx Word 文件 无法在浏览器中直接预览#xff08;尤其在私有 API 场景下#xff09;#xff0c;常见的 Content-Disposition: inline 并不能生效。因此#xff0c;本方案通过…私有 Word 文件在线预览方案.doc/.docx 转 PDF
前言
由于 .doc 和 .docx Word 文件 无法在浏览器中直接预览尤其在私有 API 场景下常见的 Content-Disposition: inline 并不能生效。因此本方案通过 后端转换为 PDF 文件并将其以文档流形式返回前端达到可在线阅读的效果。
效果如图 实现流程概览
前端请求文件非下载模式后端判断文件扩展名是否为 .doc 或 .docx使用 LibreOffice 将 Word 文件转换为 PDF待 PDF 生成后通过 res.sendFile() 发送给前端可选临时 PDF 文件使用后自动删除 实现步骤 第一步后端判断 Word 文件类型并构建 PDF 路径
const docxRegex /\.(docx?)$/i; // 支持 .doc 和 .docx忽略大小写if (type ! download docxRegex.test(filePath)) {const pdfPath filePath.replace(docxRegex, .pdf); // 替换为 PDF 路径...
}第二步安装 LibreOffice用于文件转换
Ubuntu / Debian
sudo apt update
sudo apt install libreoffice -yCentOS / RHEL
sudo yum install libreoffice -y第三步安装中文字体避免 PDF 中文乱码
推荐使用开源思源字体Noto 字体家族
Ubuntu / Debian
sudo apt install fonts-noto-cjk -yCentOS / RHEL
sudo yum install google-noto-sans-cjk-ttc -y第四步转换 Word 文件为 PDF 并返回给前端
const { exec } require(child_process);
const fs require(fs);exec(libreoffice --headless --convert-to pdf ${filePath} --outdir ${uploadDir}, (error, stdout, stderr) {if (error) {console.error(转换文件失败:, error);return res.status(500).json({ message: 转换文件失败 });}const waitForPdf setInterval(() {if (fs.existsSync(pdfPath) fs.statSync(pdfPath).size 1000) {clearInterval(waitForPdf);res.setHeader(Content-Type, application/pdf);res.sendFile(pdfPath, (err) {if (err) {console.error(发送 PDF 文件失败:, err);return res.status(500).json({ message: 发送失败 });}// 清理临时文件fs.unlink(pdfPath, (unlinkErr) {if (unlinkErr) {console.error(删除 PDF 失败:, unlinkErr);} else {console.log(临时 PDF 已删除);}});});}}, 100); // 每 100ms 检查一次 PDF 文件生成状态
});补充建议
你可以在服务器上缓存转换后的 PDF避免重复转换建议加入错误重试机制比如检测失败后尝试转换 2 次如对性能有要求可使用转换任务队列如 bull.js 示例前端预览
可以获取
// 查看文档
async viewDocument(fileData) {let update { filename: fileData.filename, userId: this.$store.state.userInfo.userId }try {// 设置 responseType 为 blob 来正确处理二进制数据const response await this.$apiRequest(get, /ser/xxxx, update, , {responseType: blob});if(response.status 200) {// 直接使用返回的 blob 数据const blob response.data;// 创建临时 URLconst blobUrl URL.createObjectURL(blob);// 在新窗口中打开文件const newWindow window.open(blobUrl, _blank);// 清理临时 URL延迟清理确保文件能正常打开setTimeout(() {URL.revokeObjectURL(blobUrl);}, 1000);// 如果无法打开新窗口提供下载选项if (!newWindow) {this.downloadFile(blob, fileData.name);}}} catch (error) {console.error(查看文档失败:, error);this.$message.error(查看文档失败请重试);}
},备注
注意responseType: blob在接口架构文件里配置一下。