代码之家  ›  专栏  ›  技术社区  ›  arcade16

如何从NodeJSAPI返回zip文件并在客户端处理?

  •  1
  • arcade16  · 技术社区  · 6 年前

    这就是我创建zip的API的样子:

    reports.get('/xxx/:fileName', async (req, res) => {
    
      var s3 = new AWS.S3();
      var archiver = require('archiver');
    
      var filenames = "xxx"
      var str_array = filenames.split(','); 
    
      for (var i = 0; i < str_array.length; i++) {
    
        var filename = str_array[i].trim();
        localFileName = './temp/' + filename.substring(filename.indexOf("/") + 1);
    
        file = fs.createWriteStream(localFileName, {flags: 'a', encoding: 'utf-8',mode: 0666});
        file.on('error', function(e) { console.error(e); });
    
        s3.getObject({
              Bucket: config.xxx,
              Key: filename
          })
          .on('error', function (err) {
              console.log(err);
          })
          .on('httpData', function (chunk) {
              file.on('open', function(){
    
                file.write(chunk);
              });
          })
          .on('httpDone', function () {
              file.end();
          })
          .send();
      }
        res.end("Files have been downloaded successfully")
    
        // create a file to stream archive data to.
        var output = fs.createWriteStream('example.zip');
        var archive = archiver('zip', {
          zlib: { level: 9 } // Sets the compression level.
        });
    
        // listen for all archive data to be written
        // 'close' event is fired only when a file descriptor is involved
        output.on('close', function() {
          console.log(archive.pointer() + ' total bytes');
          console.log('archiver has been finalized and the output file descriptor has closed.');
        });
    
        // This event is fired when the data source is drained no matter what was the data source.
        // It is not part of this library but rather from the NodeJS Stream API.
        // @see: https://nodejs.org/api/stream.html#stream_event_end
        output.on('end', function() {
          console.log('Data has been drained');
        });
    
        // good practice to catch warnings (ie stat failures and other non-blocking errors)
        archive.on('warning', function(err) {
          if (err.code === 'ENOENT') {
            // log warning
          } else {
            // throw error
            throw err;
          }
        });
    
        // good practice to catch this error explicitly
        archive.on('error', function(err) {
          throw err;
        });
    
        // pipe archive data to the file
        archive.pipe(output);
    
        // append files from a sub-directory, putting its contents at the root of archive
        archive.directory('./temp', false);
    
        // finalize the archive (ie we are done appending files but streams have to finish yet)
        // 'close', 'end' or 'finish' may be fired right after calling this method so register to them beforehand
        archive.finalize();
    
    });
    

    这里还有我的另一个API,用于说明我如何习惯于将数据发送回客户端,以供参考:

    reports.get('/xxx/:fileName', async (req, res) => {
    
      var s3 = new AWS.S3();
    
      var params = { 
        Bucket: config.reportBucket,
        Key: req.params.fileName,
        Expires: 60 * 5
      }
    
      try {
        s3.getSignedUrl('getObject', params, function (err, url) {
          if(err)throw err;
          res.json(url);
        });
      }catch (err) {
        res.status(500).send(err.toString());
      }
    });
    

    如何将zip作为响应发送回客户端并将其下载到磁盘?

    2 回复  |  直到 6 年前
        1
  •  6
  •   Thomas Jensen    6 年前

    自从 archive res ):

    // Node.js v10+, if res is a proper stream
    const {pipeline} = require('stream')
    pipeline(archive, res)
    
    // Alternatively (search for caveats of pipe vs. pipeline)
    archive.pipe(res)
    

    物件

    res.set({
      'Content-Type': 'application/zip',
      'Content-Disposition': 'attachment; filename="filename.jpg"'
    })
    
        2
  •  3
  •   Smily    6 年前

    好的,一旦你写了文件, example.zip another answer 并且做:

    var stat = fileSystem.statSync('example.zip');
    
    res.writeHead(200, {
        'Content-Type': 'application/zip',
        'Content-Length': stat.size
    });
    
    var readStream = fileSystem.createReadStream('example.zip');
    // We replaced all the event handlers with a simple call to readStream.pipe()
    readStream.pipe(res);
    

    这应该能很好地发挥作用。归功于 OP