记一次 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,优先考虑它。

相关推荐
ilvcn9 小时前
在线 PDF 翻译工具实测:整份翻译保留表格版式,长文档处理方案
pdf
DS随心转小程序10 小时前
文心文字怎么转为 word?告别繁琐排版操作,AI 导出鸭一站式完成文档转换工作
人工智能·word·豆包·deepseek·ai导出鸭
accept 99%13 小时前
python版提取 PDF 的常用第三方库与工具
开发语言·python·pdf
AI导出鸭1 天前
怎么让千问做表格?AI导出鸭苹果版将千问输出的管道表格智能解析为二维结构,一键导出为Excel或Word标准表格。
人工智能·chatgpt·word·excel·ai导出鸭
zyplayer-doc1 天前
zyplayer-doc企业知识库能做什么:从文档创建、权限管理到AI问答的完整能力
大数据·javascript·数据库·人工智能·pdf·word
小短腿乄1 天前
java实现pdf加水印+签名
java·开发语言·pdf
gb42152871 天前
python中unstructured库和langchain-unstructured库在解析pdf文件的时候的区别?
python·langchain·pdf
吹个口哨写代码2 天前
markdown转word、pdf
pdf
ElasticPDF-新国产PDF编辑器2 天前
【最新·免费PDF编辑器·不限终端·最高性价比SDK】直接编辑 PDF 原有图片!裁剪、替换、旋转与图层管理
pdf
gb42152872 天前
python中pypdf库和langchain-unstructured库在解析pdf文件的时候的区别?
python·langchain·pdf