You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

API返回PDF流转前端保存页数正确但内容空白问题排查

问题根因

PDF页数正常但全空白是二进制传输损坏的典型特征:PDF的文档结构元数据(页码、页尺寸、目录索引)没有被破坏,但承载实际渲染内容的二进制流在传输中被错误做了文本转码,导致阅读器能识别文档框架,但读不出可渲染的内容。
你已经验证服务端本地存储的源文件是正常的,问题完全出在服务端响应配置、前端请求配置两个环节。

修复步骤

1. 补全服务端响应头配置

你当前直接转发流、读取本地文件返回时,没有设置完整的二进制传输响应头,会导致Web框架、反向代理默认把响应当成普通文本处理,自动做UTF-8转码破坏二进制内容。
不管是直接代理上游API流,还是读本地文件流返回,都要在执行pipe前加全以下响应头:

// 代理上游API流的修复版代码
const streamResponse = await axios({
    url : endpoint_url,
    method: 'GET',
    headers: {
        // 原有鉴权参数保留即可
    },
    responseType: 'stream'
});
// 以下响应头必须设置,禁止中间件篡改二进制内容
res.setHeader('Content-Type', 'application/pdf');
res.setHeader('Content-Disposition', 'attachment; filename="output.pdf"');
res.setHeader('Content-Transfer-Encoding', 'binary');
// Express类框架需要关闭默认字符集编码
if (typeof res.charset !== 'undefined') res.charset = false;
streamResponse.data.pipe(res);

读取本地文件返回的场景也需要配置完全相同的响应头,不能只设置Content-Type:

const pdfFile = fs.createReadStream(pdfFilePath)
res.setHeader('Content-Type', 'application/pdf');
res.setHeader('Content-Disposition', 'attachment; filename="output.pdf"');
res.setHeader('Content-Transfer-Encoding', 'binary');
if (typeof res.charset !== 'undefined') res.charset = false;
pdfFile.pipe(res);

2. 修复前端请求配置(90%的同类问题出自这里)

你贴的Blob保存逻辑本身没有问题,但你没有贴前端发起接口请求的代码——前端发起请求时必须显式声明responseType: 'blob'(或arraybuffer),否则浏览器默认会把响应当成普通文本做UTF-8解码,直接把二进制PDF流损坏,后续不管是手动转Blob、还是用file-saver保存,拿到的都只会是结构完整但内容损坏的空白PDF。
注意:file-saver等工具库只能处理已经正确接收的二进制数据,无法修复请求阶段就已经被文本解码损坏的内容,这也是你之前换用file-saver没有效果的原因。

以axios为例的前端正确请求+保存代码:

// 发起请求时必须配置responseType,这是核心修复点
const res = await axios.get('/你的服务端PDF接口地址', {
    responseType: 'blob' // 不能用默认的text、json类型,必须选blob或arraybuffer
});
// 原有保存逻辑可以保留,补充内存释放即可
const blob = new Blob([res.data], { type: "application/pdf" });
const link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = 'output.pdf';
link.click();
window.URL.revokeObjectURL(link.href);

如果用原生fetch实现,必须用blob()方法解析响应,不能用text()、json():

fetch('/你的服务端PDF接口地址')
    .then(res => res.blob()) // 禁用res.text()
    .then(blob => {
        // 同上保存逻辑
    })
验证方法

修改完成后可以做两个快速校验确认问题修复:

  • 对比服务端原始PDF和前端下载PDF的文件字节数,两者完全一致说明传输过程没有丢包、转码
  • 用文本编辑器打开下载的PDF,开头%PDF-1.4标识后的二进制乱码部分和源文件一致,没有大量问号、Unicode替换字符,说明二进制内容没有被损坏。

内容的提问来源于stack exchange,提问作者P_RIFF

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 22:04:03