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

Node16环境下NestJS使用JSZip打包CSV为zip报blob不支持错误

报错根因

你遇到这个问题是三个错误导致的:

  • blob是浏览器环境专属的Web API,Node.js 16原生没有提供浏览器端的Blob实现,JSZip检测到当前运行环境不支持Blob就会抛出这个错误
  • FileSaver是纯前端浏览器库,唯一作用是触发浏览器的文件下载弹窗,根本无法在NestJS这类Node服务端环境运行。服务端生成文件后要么写入本地磁盘,要么通过HTTP响应返回给客户端,完全用不上FileSaver
  • 你当前的zipFiles方法根本没有把读取到的CSV文件内容添加到JSZip实例中,就算解决了Blob报错,最终生成的也是空的压缩包
修复方法

JSZip在Node环境下生成文件时,要把输出类型改成nodebuffer,这个类型会返回Node原生支持的Buffer对象,不需要额外兼容。以下是两种常用场景的可运行代码:

场景1:服务端直接将zip保存到本地磁盘

你原来的文件读取方法只返回了文件名,没有读取文件内容,需要调整逻辑,在打包流程中读取文件内容加入压缩包:

const os = require('os');
const path = require('path');
const fs = require('fs/promises');
const JSZip = require('jszip');

async function readAllFilesInDirectory() {
  const userHomeDir = os.homedir();
  // 注意此处原有路径写了多组../,建议打印tmpDir确认路径正确性,避免读错目录
  const tmpDir = path.resolve(userHomeDir, '..', '../tmp');
  console.log('读取目录路径:', tmpDir);

  try {
    const files = await fs.readdir(tmpDir);
    // 过滤后返回文件完整路径,方便后续读取内容
    return files
      .filter((file) => {
        return !(
          file.startsWith('systemd') ||
          file.startsWith('.') ||
          file.startsWith('snap') ||
          file.startsWith('ssh') ||
          file.startsWith('tracker') ||
          file.startsWith('vscode')
        );
      })
      .map(fileName => path.join(tmpDir, fileName));
  } catch (e) {
    console.error('读取目录失败:', e);
    return [];
  }
}

async function zipFiles() {
  const allFilePaths = await this.readAllFilesInDirectory();
  console.log('待打包文件列表:', allFilePaths);

  const zip = new JSZip();
  // 逐个读取文件内容加入压缩包
  for (const filePath of allFilePaths) {
    const fileName = path.basename(filePath);
    // 需求是打包CSV的话可以在这里加判断:if(!fileName.endsWith('.csv')) continue
    const fileContent = await fs.readFile(filePath);
    zip.file(fileName, fileContent);
  }

  // Node环境下用nodebuffer类型输出,不要用blob
  const zipBuffer = await zip.generateAsync({ 
    type: 'nodebuffer',
    compression: 'DEFLATE' // 开启压缩减小体积
  });

  // 将zip写入本地文件
  await fs.writeFile(path.join(__dirname, 'test.zip'), zipBuffer);
  console.log('压缩包生成成功');
}

场景2:NestJS接口返回zip给前端下载

如果是写接口让前端触发下载,不需要存本地,直接把Buffer返回给响应即可,示例:

import { Controller, Get, Res } from '@nestjs/common';
import { Response } from 'express';
// os、path、fs、JSZip、readAllFilesInDirectory方法的引入和上面保持一致即可

@Controller('export')
export class ExportController {
  @Get('csv-zip')
  async downloadCsvZip(@Res() res: Response) {
    const allFilePaths = await this.readAllFilesInDirectory();
    const zip = new JSZip();
    for (const filePath of allFilePaths) {
      const fileName = path.basename(filePath);
      const fileContent = await fs.readFile(filePath);
      zip.file(fileName, fileContent);
    }
    const zipBuffer = await zip.generateAsync({ 
      type: 'nodebuffer',
      compression: 'DEFLATE'
    });

    // 设置响应头,告诉浏览器这是文件下载
    res.set({
      'Content-Type': 'application/zip',
      'Content-Disposition': 'attachment; filename="csv-files.zip"',
      'Content-Length': zipBuffer.length
    });
    res.end(zipBuffer);
  }
}

提示:如果你确实需要在Node 16环境使用Blob类型(没有必要,Buffer兼容性更好),可以手动安装跨环境Blob实现包做全局挂载,但优先推荐直接使用nodebuffer方案,不需要额外依赖。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 20:48:19