从Nestjs下载文件(无需保存)

发布于 2025-02-02 17:19:19 字数 1492 浏览 3 评论 0原文

我想让客户端下载从我的后端生成的PDF文件。我正在使用 pdfkit-lib 生成我的pdf文件。来自Nestjs documentation ,我决定使用arthableFile duplexstream(pdfkit-lib与writableStreamstreamableFile readableStream )

@Get('/generate-file')
generateFile(): StreamableFile {
  const fileStream = new stream.Duplex();
  const doc = new pdfkit()
  doc.pipe(fileStream);
  // do stuff
  doc.end();
  return new StreamableFile(fileStream);
}

:此错误:

Error: The _write() method is not implemented
    at new NodeError (node:internal/errors:371:5)
    at Duplex.Writable._write (node:internal/streams/writable:588:11)
    at writeOrBuffer (node:internal/streams/writable:389:12)
    at _write (node:internal/streams/writable:330:10)
    at Duplex.Writable.write (node:internal/streams/writable:334:10)
    at PDFDocument.ondata (node:internal/streams/readable:754:22)
    at PDFDocument.emit (node:events:390:28)
    at PDFDocument.Readable.read (node:internal/streams/readable:527:10)
    at flow (node:internal/streams/readable:1012:34)
    at resume_ (node:internal/streams/readable:993:3)

它可以使其与fs.createwritestreamfs.createReadStream一起使用,但我不想在我的服务器上创建文件(并且在上面没有回调删除流式文件)。有什么想法吗?

I want to make client download a pdf file generated from my back-end. I am using the pdfkit-lib to generate my pdf file. From the NestJs documentation, I decided to use StreamableFile from a DuplexStream (pdfkit-lib works with a WritableStream and StreamableFile with a ReadableStream) :

@Get('/generate-file')
generateFile(): StreamableFile {
  const fileStream = new stream.Duplex();
  const doc = new pdfkit()
  doc.pipe(fileStream);
  // do stuff
  doc.end();
  return new StreamableFile(fileStream);
}

But I end up with this error :

Error: The _write() method is not implemented
    at new NodeError (node:internal/errors:371:5)
    at Duplex.Writable._write (node:internal/streams/writable:588:11)
    at writeOrBuffer (node:internal/streams/writable:389:12)
    at _write (node:internal/streams/writable:330:10)
    at Duplex.Writable.write (node:internal/streams/writable:334:10)
    at PDFDocument.ondata (node:internal/streams/readable:754:22)
    at PDFDocument.emit (node:events:390:28)
    at PDFDocument.Readable.read (node:internal/streams/readable:527:10)
    at flow (node:internal/streams/readable:1012:34)
    at resume_ (node:internal/streams/readable:993:3)

It can make it works with fs.createWriteStream and fs.createReadStream but I don't want to create the file on my server (and there is no callback on StreamableFile to delete). Any idea ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

谁把谁当真 2025-02-09 17:19:19

我最终使用fs.createwritestreamfs.CreateReadStream通过删除创建的文件:

@Get('/generate-file')
generateFile(@Res({ passthrough: true }) res: Response): StreamableFile {
  const fileName = '';
  const filePath = '';
  
  const doc = new pdfkit()
  doc.pipe(fs.createWriteStream(filePath));
  // do stuff
  doc.end();

  const fileStream = fs.createReadStream(filePath);

  fileStream.on('end', () => {
    try {
      fs.unlinkSync(filePath);
    } catch (error) {
      throw new BadRequestException('An error occurred while removing the file.');
    }
  });

  res.set({
    'Content-Type': 'application/pdf',
    'Content-Disposition': `attachment; filename="${fileName}"`,
  });
  return new StreamableFile(fileStream);
}

I end up using fs.createWriteStream and fs.createReadStream by deleting the created file :

@Get('/generate-file')
generateFile(@Res({ passthrough: true }) res: Response): StreamableFile {
  const fileName = '';
  const filePath = '';
  
  const doc = new pdfkit()
  doc.pipe(fs.createWriteStream(filePath));
  // do stuff
  doc.end();

  const fileStream = fs.createReadStream(filePath);

  fileStream.on('end', () => {
    try {
      fs.unlinkSync(filePath);
    } catch (error) {
      throw new BadRequestException('An error occurred while removing the file.');
    }
  });

  res.set({
    'Content-Type': 'application/pdf',
    'Content-Disposition': `attachment; filename="${fileName}"`,
  });
  return new StreamableFile(fileStream);
}
梦魇绽荼蘼 2025-02-09 17:19:19

如果不写临时文件的开销,应该可以执行此操作。您可以尝试直接流式传输到res流中,类似:

@Get('/generate-file')
generateFile(@Res() res: Response): void {
   const filename = 'SomeFileName.pdf';
   const doc = new PDFDocument({ bufferPages: true });
   const stream = res.writeHead(200, {
    'Content-Type': 'application/pdf',
    'Content-disposition': `attachment;filename=${filename}.pdf`,
   });
   doc.on('data', (chunk) => stream.write(chunk));
   doc.on('end', () => stream.end());

   doc
     .font('Times-Roman')
     .fontSize(12)
     .text(`just a test`);
   doc.end();
 }

It should be possible to do this without the overhead of writing to a temporary file. You can try streaming directly into the res stream, something like:

@Get('/generate-file')
generateFile(@Res() res: Response): void {
   const filename = 'SomeFileName.pdf';
   const doc = new PDFDocument({ bufferPages: true });
   const stream = res.writeHead(200, {
    'Content-Type': 'application/pdf',
    'Content-disposition': `attachment;filename=${filename}.pdf`,
   });
   doc.on('data', (chunk) => stream.write(chunk));
   doc.on('end', () => stream.end());

   doc
     .font('Times-Roman')
     .fontSize(12)
     .text(`just a test`);
   doc.end();
 }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文