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

Nest.js中Puppeteer生成PDF本地正常但Blob返回文件损坏求助

我之前也碰到过一模一样的问题!折腾了好久才搞定,大概率是二进制内容在传输或处理过程中被意外编码/修改导致的,咱们一步步来排查解决:

1. 补全响应头,避免客户端解析混乱

你已经设置了Content-Type,但建议再加上Content-Disposition头,明确告诉浏览器这是可下载的PDF文件,同时防止某些客户端对二进制内容做额外处理:

@Post('invoice')
@Header('Content-Type', 'application/pdf')
@Header('Content-Disposition', 'attachment; filename="invoice.pdf"') // 新增这行
async generateInvoice(@Body() invoice: InvoiceDto): Promise<Buffer> {
  return await this.service.generateInvoice(invoice);
}

2. 改用Nest.js推荐的StreamableFile返回二进制内容

直接返回Buffer有时候会被全局拦截器/自动编码搞砸,用StreamableFile能确保Nest.js正确处理二进制流,避免不必要的转换:
首先引入依赖:

import { StreamableFile } from '@nestjs/common';
import { PassThrough } from 'stream';

然后修改控制器方法:

async generateInvoice(@Body() invoice: InvoiceDto): Promise<StreamableFile> {
  const pdfBuffer = await this.service.generateInvoice(invoice);
  // 把Buffer转成可读流
  const stream = new PassThrough();
  stream.end(pdfBuffer);
  
  return new StreamableFile(stream, {
    type: 'application/pdf',
    disposition: 'attachment; filename="invoice.pdf"',
  });
}

3. 检查前端fetch请求的responseType设置

前端如果没指定responseType: 'arraybuffer',会默认把响应当成文本解析,直接破坏PDF的二进制结构,一定要加上:

fetch('/pdf/invoice', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(yourInvoiceData),
})
.then(response => {
  // 必须先确认响应状态正常
  if (!response.ok) throw new Error('请求失败');
  return response.arrayBuffer(); // 这里一定要用arrayBuffer,不能用text()
})
.then(buffer => {
  const blob = new Blob([buffer], { type: 'application/pdf' });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = 'invoice.pdf';
  a.click();
  URL.revokeObjectURL(url); // 记得释放内存
});

4. 验证服务生成的Buffer本身是否正常

先排除服务端生成的PDF有问题:在PdfService里临时把生成的Buffer写入本地文件,看看能不能正常打开:

async generateInvoice(invoiceData: InvoiceDto): Promise<Buffer> {
  // ... 现有代码
  const pdfBuffer = await page.pdf({format: 'A4'});
  // 临时写入本地验证
  fs.writeFileSync('test-local.pdf', pdfBuffer);
  return pdfBuffer;
}

如果这个本地文件能正常打开,说明服务端生成没问题,问题肯定出在响应传输或前端处理。

5. 排查全局拦截器/过滤器是否篡改了响应

如果你的项目里有全局响应拦截器(比如统一返回{ code: 200, data: ... }的格式),那它会把PDF Buffer包裹成JSON对象,直接破坏二进制内容。要给这个PDF接口加个例外:

  • 在控制器方法上用@SkipInterceptor(YourGlobalInterceptor)跳过拦截(如果你的拦截器支持)
  • 或者在拦截器逻辑里判断请求路径,比如如果是/pdf/invoice就直接返回原响应,不做包装。

按照上面的步骤走,基本就能解决问题了!我当时就是因为全局拦截器把PDF包成了JSON,导致下载的文件全是乱码😂

内容的提问来源于stack exchange,提问作者Jakub Wąsowski

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:42:16