Express res.download返回PDF 前端Blob下载内容为undefined排查
问题根因
故障和后端res.download逻辑无关,完全是前端Promise链式调用的写法错误导致的:
你在处理下载接口响应的第一个.then()回调里,没有返回res2.blob()的Promise结果,导致下一个.then()接收到的入参是默认的undefined,最终被写入Blob生成文件的内容就是字符串undefined,和你排查到的现象完全吻合。
错误代码片段对应位置:
// 错误写法 .then((res2) => { res2.blob() // 箭头函数包裹在大括号内时,没有return就会返回undefined // blob()本身是异步方法,返回Promise,不return的话外层拿不到解析后的Blob对象 }) .then((blob)=>{ // 这里的blob实际是上一个回调的返回值undefined const newBlob = new Blob([blob]); // 把undefined转成字符串"undefined"存入文件 // 后续下载逻辑拿到的自然是内容错误的文件 })
除此之外你的前端代码还有两个小问题:
- 多余做了一层
new Blob([blob])包装:res2.blob()本身就返回标准Blob对象,不需要重复包装 window.URL.revokeObjectURL传参错误:该方法需要传入之前生成的对象URL,你之前传的是Blob对象,会导致临时URL无法被释放,造成内存泄漏
修复代码
前端下载逻辑修正
把前端下载部分的代码替换为以下内容即可解决核心问题:
fetch(downloadUrl, { method: "POST", headers: { 'Content-Type': 'application/json', }, body: dataString, }) .then(res2 => { if (!res2.ok) throw new Error('下载请求异常'); return res2.blob(); // 必须return,把Blob结果传递给下一个then链 }) .then(blob => { const objectUrl = window.URL.createObjectURL(blob); const link = document.createElement('a'); link.href = objectUrl; link.download = 'certificate.pdf'; document.body.appendChild(link); link.click(); link.remove(); window.URL.revokeObjectURL(objectUrl); // 传入生成的临时URL释放内存 }) .catch(err => { console.error('证书下载失败:', err); alert('证书下载出错,请重试'); })
后端逻辑优化(非必须,建议补充)
你当前后端代码没有处理PDF生成失败、文件发送失败的场景,出错时前端会一直等待无响应,建议补充错误返回:
const getCertificatePDF = (name, validValuesData, validValuesQty, response) => { // ... 省略前置逻辑 pdf.create(document, options) .then(res => { const filePath = path.join(__dirname, 'certificate.pdf'); response.download(filePath, "certificate.pdf", err => { if (err) { console.error('文件发送失败:', err); response.status(500).send('下载失败'); } }); }) .catch(error => { console.error('PDF生成失败:', error); response.status(500).send('证书生成失败'); }); }
验证方法
修复后重新测试:
- 下载得到的PDF文件大小和服务器本地生成的
certificate.pdf大小完全一致 - 打开文件可以正常显示证书内容,不会再出现仅包含
undefined的情况 - 控制台无请求报错
内容的提问来源于stack exchange,提问作者nluizsoliveira
相关产品推荐
相关产品推荐

