expresshttpnestjssendfile

Nest.js and Archiver - pipe stream zip file into http response


In my node.js application I'm downloading multiple user files from AWS S3, compress them to single zip (with usage of Archiver npm library) file and send back to client. All the way I'm operating on streams, and yet I can't send files to client (so client would start download after successful http request).

const filesStreams = await this.awsService.downloadFiles(
    document?.documentFiles,
  );
const zipStream = await this.compressService.compressFiles(filesStreams);

  // ts-ignore
  response.setHeader('Content-Type', 'application/octet-stream');
  response.setHeader(
    'Content-Disposition',
    'attachment; filename="files.zip"',
  );
  zipStream.pipe(response);

Where response is express response object. zipStream is created with usage of Archiver:

public async compressFiles(files: DownloadedFileType[]): Promise<Archiver> {
const zip = archiver('zip');

for (const { stream, name } of files) {
  zip.append((stream as unknown) as Readable, {
    name,
  });
}

return zip;

And I know it is correct - because when I pipe it into WriteStream to some file in my file system it works correctly (I'm able to unzip written file and it has correct content). Probably I could temporarily write file in file system, send it back to client with usage of response.download and remove save file afterwards, but it looks like very inefficient solution. Any help will be greatly appreciated.


Solution

  • So I found a source of a problem - I'll post it here just for record, in case if anyone would have same problem. Source of the problem was something totally different - I was trying to initiate a download by AJAX request, which of course won't work. I changed my frontend code and instead AJAX I used HTML anchor element with src attribute set on exactly same endpoint and it worked just fine.