PDF 是商务文档、电子合同、发票、报告等场景中最常见的文件格式之一。在开发中,我们经常需要将 PDF 文件转换为 Base64 字符串,以便在 JSON 接口中传输、存储到数据库、或嵌入到前端页面中预览;反过来,也经常收到前端传来的 Base64 字符串,需要将其还原为 PDF 文件保存到服务器或提供给用户下载。虽然原理上与普通二进制文件转 Base64 一致,但 PDF 的大体积、特殊格式以及浏览器端的展示需求,让这个转换过程有不少值得注意的细节。本文将从实际应用出发,详细介绍 PDF 与 Base64 互转的完整方案,包括在线工具和代码实现两种路径,并覆盖浏览器端、Node.js 后端、Python 等环境。

读完本文,你将掌握:如何在浏览器中读取用户上传的 PDF 并转为 Base64;如何在后端接收 Base64 并保存为 PDF 文件;如何构建可下载的 PDF Data URL;以及如何避免内存溢出、乱码和文件损坏等常见问题。

一、为什么需要将 PDF 与 Base64 互转?

在 Web 系统中,PDF 文件通常作为二进制流存在。但许多通信协议和存储格式(如 JSON、XML、数据库的文本字段)不支持直接存放二进制数据。Base64 提供了一种将 PDF 文件表示为纯 ASCII 字符串的方式,使其能够在这些场景中安全传递。典型用途包括:

  • API 传输:前端通过 AJAX 将 Base64 编码的 PDF 发送到后端,或者后端将 PDF 以 Base64 字段返回给前端,方便在 <iframe><object> 中预览。
  • 存储:某些数据库字段(如 MySQL 的 TEXT 类型)不适合存储二进制,Base64 字符串可以直接存入,需要时再解码还原。
  • 邮件附件:通过 SMTP 发送带 PDF 附件的邮件时,附件内容可使用 Base64 编码。
  • 前端离线预览:在没有后端存储的情况下,将 PDF 转为 Data URL 直接嵌入页面,实现即时的文档查看。

需要注意的是,Base64 编码会使文件体积增加约 33%。对于一个 5MB 的 PDF,Base64 字符串大约是 6.7MB。如果接口传输或存储大量 PDF,建议谨慎评估是否使用 Base64,还是直接使用 multipart/form-data 文件上传或对象存储服务。

二、浏览器端:将 PDF 文件转换为 Base64

在前端,获取用户选择的 PDF 文件后,可以使用 FileReaderreadAsDataURL 方法直接得到包含 Base64 的 Data URL,也可以通过 readAsArrayBuffer 结合手动编码获得纯 Base64 字符串。

  • 使用 FileReader.readAsDataURL(最简单):

    const input = document.getElementById('pdfInput');

    input.addEventListener('change', (e) => {

      const file = e.target.files[0];

      const reader = new FileReader();

      reader.onload = (ev) => {

        const dataUrl = ev.target.result; // data:application/pdf;base64,....

        const base64 = dataUrl.split(',')[1]; // 纯 Base64 字符串

      };

      reader.readAsDataURL(file);

    });

  • 手动将 ArrayBuffer 转为 Base64:如果不想包含 Data URL 前缀,可以使用 FileReader.readAsArrayBuffer 得到字节,然后利用 String.fromCharCodebtoa 转换。注意 btoa 有大小限制,大文件建议分块处理。
  • 使用 Blob 和 FileReader:对于 Blob 对象(例如从 canvas 或 fetch 获取),同样可以使用 FileReader.readAsDataURL(blob)

三、前端:将 Base64 还原为 PDF 预览或下载

当后端返回 Base64 编码的 PDF 时,前端可以通过以下几种方式展示或提供下载:

  • 使用 Data URL 直接嵌入 iframe/object:

    const base64 = '...'; // 从后端获取

    const pdfDataUrl = 'data:application/pdf;base64,' + base64;

    document.getElementById('pdfViewer').src = pdfDataUrl;

    其中 pdfViewer 是一个 <iframe><embed> 元素。

  • Blob + URL.createObjectURL 下载:

    const byteCharacters = atob(base64);

    const byteArray = new Uint8Array(byteCharacters.length);

    for (let i = 0; i < byteCharacters.length; i++) { byteArray[i] = byteCharacters.charCodeAt(i); }

    const blob = new Blob([byteArray], { type: 'application/pdf' });

    const url = URL.createObjectURL(blob);

    const a = document.createElement('a');

    a.href = url; a.download = 'document.pdf'; a.click();

    URL.revokeObjectURL(url);

  • 直接打开新窗口:window.open(pdfDataUrl, '_blank') 也可以,但部分浏览器会阻止弹窗,移动端体验不佳。

四、Node.js 后端:PDF 转 Base64 与还原保存

在 Node.js 中,可以使用内置的 fsBuffer 模块轻松完成 PDF 与 Base64 的互转。以下示例适用于 Express/Koa 等框架。

  • PDF 文件转 Base64 字符串:

    const fs = require('fs');

    const pdfBuffer = fs.readFileSync('report.pdf');

    const base64Pdf = pdfBuffer.toString('base64');

    若需返回 Data URL:const dataUrl = 'data:application/pdf;base64,' + base64Pdf;

  • 接收 Base64 并保存为 PDF 文件:

    const base64Data = req.body.base64; // 假设前端传来纯 Base64

    const pdfBuffer = Buffer.from(base64Data, 'base64');

    fs.writeFileSync('output.pdf', pdfBuffer);

  • 处理大文件流:如果 PDF 较大(>100MB),建议使用流式读取 fs.createReadStream 并通过 base64-stream 等库编码,避免内存峰值过高。
  • 设置响应头提供下载:res.setHeader('Content-Type', 'application/pdf'); res.setHeader('Content-Disposition', 'attachment; filename="doc.pdf"'); res.send(pdfBuffer);

五、Python 中 PDF 与 Base64 互转

Python 处理 PDF Base64 与处理普通文件并无本质区别,依旧依赖 base64 模块和二进制文件读写。以下是一些实用片段:

  • PDF 转 Base64:

    with open('document.pdf', 'rb') as f:

      base64_str = base64.b64encode(f.read()).decode('ascii')

  • Base64 还原 PDF:

    with open('restored.pdf', 'wb') as f:

      f.write(base64.b64decode(base64_str))

  • 处理 JSON 接口中的 Base64:从 JSON 中取出字段后,先确认是否是纯 Base64 还是完整 Data URL,再进行解码。
  • 大文件优化:使用 shutil.copyfileobj 配合 io.BytesIO 或分块编码,避免一次性读入内存。

六、在线工具与命令行方案

对于临时、非敏感的 PDF 转换需求,在线工具可以快速解决问题。但务必注意隐私:PDF 可能包含合同、身份证等敏感信息,请勿上传到不可信的第三方网站。更推荐使用本地命令行:

  • Linux/macOS:

    base64 -i input.pdf -o output.txt # 编码

    base64 -d -i output.txt -o restored.pdf # 解码

  • Windows PowerShell:

    [Convert]::ToBase64String([IO.File]::ReadAllBytes("C:\input.pdf"))

    [IO.File]::WriteAllBytes("C:\output.pdf", [Convert]::FromBase64String($base64Str))

在线工具通常支持拖拽上传、自动识别 MIME、即时预览,但在传输大文件时可能受上传大小限制,也不适合批量操作。

七、常见问题与注意事项

  • 解码后的 PDF 打不开:检查 Base64 字符串是否完整、是否包含换行符(需要移除);确认没有误删除填充符 '=';确认前端传来的字符串是否包含 Data URL 前缀,需要先剥离。
  • 中文文件名乱码:Base64 只处理文件内容,不包含文件名。文件名应通过 HTTP 头或 JSON 字段单独传递,并确保 UTF-8 编码。
  • 接口体积过大:如果 PDF 超过几 MB,使用 Base64 会让 JSON 请求/响应变得非常庞大。考虑改用 multipart/form-data 上传、对象存储直传,或者在后端之间使用二进制流传输。
  • 移动端内存限制:在浏览器中处理大型 PDF Base64 字符串可能导致页面卡顿或内存溢出,建议限制上传文件大小,或者使用 StreamSaver.js 等流式下载方案。
  • 安全性:不要盲目信任前端传来的 MIME 类型或文件扩展名,解码后应验证 PDF 文件头(%PDF)以确保文件完整性。

八、总结:选择合适的转换策略

PDF 与 Base64 的互转本身并不复杂,关键在于根据文件大小、使用场景和性能要求选择最合适的方案。对于小于 1MB 的 PDF,直接使用 Base64 字符串嵌入 JSON 传输非常方便;对于较大的文件,务必考虑流式处理和二进制直传,避免不必要的内存和带宽开销。

无论是使用在线工具临时处理,还是在前端、Node.js、Python 中编写自动化代码,掌握了本文介绍的方法和注意事项,你就能在 PDF 文档处理流程中游刃有余。下一次遇到"PDF转Base64"或"Base64还原PDF"的需求时,不妨直接从你的代码库中调用现成函数,而不是每次都去搜索在线工具。