【问题标题】:Piping zip file from SailsJS backend to React Redux Frontend将 zip 文件从 SailsJS 后端传送到 React Redux 前端
【发布时间】:2017-05-30 01:15:56
【问题描述】:

我有一个 SailsJS 后端,我在其中生成一个 zip 文件,这是我的前端(一个带有 Redux 的 React 应用程序)请求的。我将Sagas 用于异步调用,fetch 用于请求。在后端,它尝试了类似的东西:

//zipFilename is the absolute path 
res.attachment(zipFilename).send();

res.sendfile(zipFilename).send();

res.download(zipFilename)send();

或使用管道传输流:

const filestream = fs.createReadStream(zipFilename);
filestream.pipe(res);

在我的前端我尝试解析它:

parseJSON(response) => {
  return response.clone().json().catch(() => response.text());
}

我尝试的一切都以一个空的 zip 文件结束。有什么建议吗?

【问题讨论】:

    标签: javascript reactjs express redux sails.js


    【解决方案1】:

    您尝试的选项存在各种问题:

    • res.attachment 只会设置 Content-TypeContent-Disposition 标头,但实际上不会发送任何内容。

      您可以使用它来正确设置标头,但您还需要将 ZIP 文件通过管道传输到响应中。

    • res.sendfile:在这之后你不应该打电话给.send()。来自官方文档的示例:

      app.get('/file/:name', function (req, res, next) {
          var options = { ... };
      
          res.sendFile(req.params.name, options, function (err) {
               if (err) {
                  next(err);
              } else {
                  console.log('Sent:', fileName);
              }
          });
      });
      

      如果 ZIP 正确构建,只要文件具有正确的扩展名,这应该可以正常工作并设置正确的 Content-Type 标头。

    • res.download:同样的事情,你不应该在这之后打电话给.send()。来自官方文档的示例:

      res.download('/report-12345.pdf', 'report.pdf', function(err) { ... });
      

      res.download 将使用res.sendfile 将文件作为附件发送,从而设置Content-TypeContent-Disposition 标头。

    但是,您提到正在发送 ZIP 文件但它是空的,因此您可能应该检查是否正确创建了 ZIP 文件。只要它们构建正确并且扩展名是.zipres.download 应该可以正常工作。

    如果您是即时构建它们,请查看以下内容:

    此中间件将动态创建一个包含多个文件的 ZIP 文件,并将其作为附件发送。它使用lazystreamarchiver

    const lazystream = require('lazystream');
    const archiver = require('archiver');
    
    
    function middleware(req, res) { 
        // Set the response's headers:
        // You can also use res.attachment(...) here.
    
        res.writeHead(200, {
            'Content-Type': 'application/zip',
            'Content-Disposition': 'attachment; filename=DOWNLOAD_NAME.zip',
        });
    
        // Files to add in the ZIP:
    
        const filesToZip = [
            'assets/file1',
            'assets/file2',
        ];
    
        // Create a new ZIP file:
    
        const zip = archiver('zip');
    
        // Set up some callbacks:
    
        zip.on('error', errorHandler);
    
        zip.on('finish', function() {
            res.end(); // Send the response once ZIP is finished.
        });
    
        // Pipe the ZIP output to res:  
    
        zip.pipe(res);
    
        // Add files to ZIP:
    
        filesToZip.map((filename) => {
            zip.append(new lazystream.Readable(() => fs
                .createReadStream(filename), {
                   name: filename,
                });
        });
    
        // Finalize the ZIP. Compression will start and output will
        // be piped to res. Once ZIP is finished, res.end() will be 
        // called.
    
        zip.finalize();
    }
    

    您可以围绕此进行构建以缓存已构建的 ZIP,而不是每次都即时构建它们,这既耗时又耗费资源,并且对于大多数用例来说完全不可取。

    【讨论】:

    • 是的,你是对的。我最终得到了res.download(); 我的主要问题是,从请求回调中获取 ArrayBuffer。它现在可以工作了,感谢您的详细回答!
    猜你喜欢
    • 2021-02-06
    • 2023-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-05
    • 2019-05-25
    相关资源
    最近更新 更多