记一次 Word 转 PDF 功能故障排查与修复

背景

最近在测试在线小工具(IEasyTool)站点时,发现 Word 转 PDF 功能突然用不了了,点击转换后直接报错:

转换失败: class com.documents4j.conversion.msoffice.MicrosoftWordBridge could not be created by a (File, long, TimeUnit) constructor

本文记录这次故障的排查过程和解决方案。


一、排查过程

1.1 定位错误来源

错误堆栈指向 documents4j 库。后台转换代码位于 FileConvertServiceImpl.java,核心实现如下:

java 复制代码
IConverter converter = LocalConverter.builder().build();
converter.convert(is).as(DocumentType.DOCX).to(os).as(DocumentType.PDF).execute();

1.2 翻历史日志

src/logs/ 目录下找到 6 月 21 号的日志,发现当时转换成功过

复制代码
MicrosoftWordBridge : From-Microsoft-Word-Converter was started successfully
LocalConverter     : The documents4j local converter has started successfully

但注意看路径------全是 C:\Users\jaime.yu\AppData\Local\Temp\...,这是 Windows 开发机的路径。

1.3 找到根因

对比环境后发现:

环境 OS 有无 MS Office 结果
开发机 Windows 11 有(Microsoft 365) 成功
生产服务器 Linux (CentOS) 失败

documents4j 的工作原理 是启动本机的 Microsoft Word 进程(通过 COM/Automation),让 Word 打开 .docx 文件,再另存为 PDF。所以它必须在安装了 Microsoft Office 的 Windows 机器上运行

生产环境是 Linux 服务器,根本没有 WINWORD.EXEMicrosoftWordBridge 自然创建失败。

该功能从一开始在生产环境就没正常过------6 月 21 日的成功日志全是本地开发机的。


二、解决方案

方案选型

方案 优点 缺点
装 Windows Server + Office 保真度最高 授权费贵、部署重
Aspose.Words(商业库) 纯 Java、保真度高 商业授权,按年付费
LibreOffice headless 免费、跨平台、保真度好 需要额外安装
Apache POI + PDFBox 纯 Java、无额外依赖 复杂排版丢失严重

最终选择 LibreOffice headless------免费、跨平台、Word 转 PDF 效果接近原生,是 Linux 上做 Office 转换的事实标准。

实现

改造后的 wordToPdf() 方法:

java 复制代码
@Override
public File wordToPdf(MultipartFile file) throws Exception {
    Path inputFile = tempDir.resolve("in_" + UUID.randomUUID() + ".docx");
    Path outputFile = tempDir.resolve("out_" + UUID.randomUUID() + ".pdf");
    try {
        file.transferTo(inputFile);
        String loPath = findLibreOffice();
        ProcessBuilder pb = new ProcessBuilder(
                loPath, "--headless", "--convert-to", "pdf",
                "--outdir", tempDir.toString(), inputFile.toString());
        pb.redirectErrorStream(true);
        Process p = pb.start();
        boolean finished = p.waitFor(120, TimeUnit.SECONDS);
        if (!finished) {
            p.destroyForcibly();
            throw new RuntimeException("LibreOffice conversion timed out after 120s");
        }
        // ... 读取输出、校验退出码、定位生成的 PDF ...
        Path generatedPdf = tempDir.resolve(inputFile.getFileName().toString()
                .replaceFirst("\\.docx$", ".pdf"));
        Files.move(generatedPdf, outputFile, StandardCopyOption.REPLACE_EXISTING);
        return outputFile.toFile();
    } finally {
        Files.deleteIfExists(inputFile);
    }
}

自动探测 LibreOffice 位置,兼容 Windows / Linux:

java 复制代码
private String findLibreOffice() {
    // Windows
    String[] winPaths = {
            "C:\\Program Files\\LibreOffice\\program\\soffice.exe",
            "C:\\Program Files (x86)\\LibreOffice\\program\\soffice.exe"};
    for (String p : winPaths) {
        if (new File(p).exists()) return p;
    }
    // Linux / macOS
    String[] nixNames = {"libreoffice", "soffice"};
    for (String name : nixNames) {
        try {
            ProcessBuilder pb = new ProcessBuilder(name, "--version");
            Process p = pb.start();
            if (p.waitFor(5, TimeUnit.SECONDS) && p.exitValue() == 0) {
                return name;
            }
        } catch (Exception ignored) {}
    }
    throw new RuntimeException("LibreOffice not found.");
}

生产环境安装 LibreOffice

bash 复制代码
# CentOS / RHEL
sudo yum install -y libreoffice-headless

# Ubuntu / Debian  
sudo apt-get install -y libreoffice-headless

# 手动安装(最可靠)
# 下载安装包
cd /tmp && \
wget https://downloadarchive.documentfoundation.org/libreoffice/old/7.5.9.2/rpm/x86_64/LibreOffice_7.5.9.2_Linux_x86-64_rpm.tar.gz && \

# 解压并安装
tar -xzf LibreOffice_7.5.9.2_Linux_x86-64_rpm.tar.gz && \
cd LibreOffice_7.5.9.2_Linux_x86-64_rpm/RPMS && \
dnf localinstall -y *.rpm && \

# 创建软链接
ln -sf /opt/libreoffice7.5/program/soffice /usr/local/bin/libreoffice && \

# 用简单文本测试转换功能
echo "test content" > /tmp/test.txt
libreoffice --headless --convert-to pdf /tmp/test.txt --outdir /tmp
ls -l /tmp/test.pdf

三、顺手修了另一个坑

同一天还修了 IP 归属地查询功能失效的问题,根因类似:

前端 LocationQuery.vue 直接用 fetch 调两个第三方 API:

  • 主 API https://ipapi.co/ → CORS 限制,浏览器拦截
  • 备 API http://ip-api.com/HTTP 明文,但生产环境强制 HTTPS,触发浏览器 Mixed Content 策略

两个都挂了,错误被 catch 静默吞掉,用户点查询完全没反应。

修法 :在后端加一个 /api/pub/ip/query 代理接口,由服务端转发请求。前端不再直接调第三方 API。


四、总结

  1. 开发环境 vs 生产环境 :像 documents4j 这种绑定特定 OS/软件的库,在开发机正常不代表生产环境正常。部署前一定要确认生产环境的 OS 和依赖。

  2. 第三方 API 不要从前端直调:浏览器有 CORS、Mixed Content 等安全策略,不确定目标 API 是否支持跨域访问时,统一走后端代理更稳妥。

  3. 异常不要静默吞掉catch(e){} 让排查问题变得非常困难。至少打个日志,或者在前端给用户一个明确的错误提示。

  4. LibreOffice headless 是 Linux 上做 Office 文档转换的标配方案,免费且效果好。如果你的项目需要在 Linux 上转 Word / Excel / PPT,优先考虑它。

相关推荐
拆房老料2 天前
ONLYOFFICE AI Agent 深度解析:在线 Office 正从编辑器走向智能工作平台
人工智能·中间件·编辑器·word·开源软件
随手工具-Excel, pdf, SQL2 天前
PDF拆分怎么操作?免费在线拆分PDF文件,无需安装任何软件
pdf
正在走向自律2 天前
实战心得:利用PaddleOCR彻底解决大模型无法解析图片型PDF的问题
开发语言·pdf·视觉检测·paddleocr·视觉模型·离线ocr识别
AI原来如此2 天前
零基础教程:50页PDF一键浓缩成1页摘要
人工智能·ai·pdf·大模型
186******205312 天前
PDF 转 Word 高效办公实战指南
pdf·word
随手工具-Excel, pdf, SQL2 天前
PDF删除页面怎么操作?免费在线删除PDF指定页面,无需安装软件
pdf
SunnyDays10113 天前
Java 实现 PDF 页面删除、排序、旋转和裁剪
java·pdf
zyplayer-doc3 天前
个人 AI 知识库怎么搭建:用 zyplayer-doc 把笔记、PDF 和图片资料变成可问答的第二大脑
大数据·开发语言·人工智能·笔记·pdf·ocr
patrickpdx3 天前
Word批量修改指定字符的字体
word·word2016