【问题标题】:Client download of a server generated zip file客户端下载服务器生成的 zip 文件
【发布时间】:2016-10-23 06:15:34
【问题描述】:

在有人说“重复”之前,我只是想确保人们知道,我已经审查了这些问题:

1) 使用 angular 和 php,不知道这里发生了什么(我不懂 PHP):Download zip file and trigger "save file" dialog from angular method

2) 无法得到这个答案来做任何事情:how to download a zip file using angular

3) 这个人已经可以下载了,这已经超出了我想要弄清楚的点: Download external zip file from angular triggered on a button action

4) 这个没有答案: download .zip file from server in nodejs

5) 我什至不知道这是什么语言: https://stackoverflow.com/questions/35596764/zip-file-download-using-angularjs-directive

鉴于这些问题,如果这仍然是重复的,我深表歉意。这是这个问题的另一个版本。

我的 Angular 1.5.X 客户端给了我一个标题列表,每个标题都有一个关联的文件。我的 Node 4.X/Express 4.X 服务器获取该列表,获取文件位置,使用 npm 中的 express-zip 创建一个 zip 文件,然后将该文件流式传输回响应中。然后我希望我的客户启动浏览器的“下载文件”选项。

这是我的客户端代码(Angular 1.5.X):

function bulkdownload(titles){
    titles = titles || [];
    if ( titles.length > 0 ) {
        $http.get('/query/bulkdownload',{
            params:{titles:titles},
            responseType:'arraybuffer'
        })
        .then(successCb,errorCb)
        .catch(exceptionCb);
    }

    function successCb(response){
        // This is the part I believe I cannot get to work, my code snippet is below
    };

    function errorCb(error){
            alert('Error: ' + JSON.stringify(error));
    };

    function exceptionCb(ex){
            alert('Exception: ' + JSON.stringify(ex));
    };
};

带有express-zip的节点(4.X)代码,https://www.npmjs.com/package/express-zip:

router.get('/bulkdownload',function(req,resp){
    var titles = req.query.titles || [];

    if ( titles.length > 0 ){
        utils.getFileLocations(titles).
        then(function(files){
            let filename = 'zipfile.zip';

            // .zip sets Content-Type and Content-disposition
            resp.zip(files,filename,console.log);
        },
        _errorCb)
    }
});

这是我的客户端代码(Angular 1.5.X)中的successCb:

function successCb(response){
    var URL = $window.URL || $window.webkitURL || $window.mozURL || $window.msURL;
    if ( URL ) {
        var blob = new Blob([response.data],{type:'application/zip'});
        var url = URL.createObjectURL(blob);
        $window.open(url);
    }
};

“blob”部分似乎工作正常。在 IE 的调试器中检查它,它看起来确实像一个八位字节信息的文件流。现在,我相信我需要将该 blob 放入一些 HTML5 指令中,以从浏览器启动“文件另存为”。可能是?也许不是?

由于我们 90% 以上的用户使用 IE11,我在 PhantomJS (Karma) 和 IE 中测试了我所有的 Angular。当我运行代码时,我在警报窗口中收到旧的“访问被拒绝”错误:

Exception: {"description":"Access is denied...<stack trace>}

欢迎提出建议、澄清、回答等!

【问题讨论】:

  • 那么会发生什么?它在什么时候失败?您是否碰巧有弹出窗口阻止程序?
  • 有什么错误吗?如果手动输入 url http://localhost/query/bulkdownload?titles=123 可以下载文件吗?
  • 哦,拍!抱歉,让我更新一下。
  • Roland Starke:当我这样做时,浏览器似乎只是在旋转,但最终,是的,它返回了一个 _tmp_zipfile.zip!但是,我调试了服务器代码,并且我得到了正确的标题数组、文件位置,并且它被正确地注入到 resp.zip 中,据我从一系列 console.logs 中可以看出。
  • 也许 ie 将 blob 作为跨域处理?如果您像window.open('/query/bulkdownload?title=xxx'); 那样直接打开网址,您可以跳过整个 ajax blob 内容,但正如 idbehold 所说,这可能是由于 pupup 阻止程序而被阻止的。这里有一些方法:stackoverflow.com/questions/11620698/…

标签: javascript angularjs node.js express zip


【解决方案1】:
var zip_file_path = "" //put inside "" your path with file.zip
var zip_file_name = "" //put inside "" file name or something
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
a.href = zip_file_path;
a.download = zip_file_name;
a.click();
document.body.removeChild(a);

【讨论】:

  • 压缩文件没有 zip_file_name。我们怎样才能让 zip 文件取这个名字 'zip_file_name' ?
【解决方案2】:

使用这个:

var url="YOUR ZIP URL HERE";
window.open(url, '_blank');

【讨论】:

    【解决方案3】:

    我更新了我的bulkdownload 方法以使用$window.open(...) 而不是$http.get(...):

    function bulkdownload(titles){
        titles = titles || [];
        if ( titles.length > 0 ) {
            var url = '/query/bulkdownload?';
            var len = titles.length;
            for ( var ii = 0; ii < len; ii++ ) {
                url = url + 'titles=' + titles[ii];
                if ( ii < len-1 ) {
                    url = url + '&';
                }
            }
            $window.open(url);
        }
    };
    

    我只在 IE11 中测试过这个。

    【讨论】:

      【解决方案4】:

      如this answer所示,我使用了下面的Javascript函数,现在我可以成功下载byte[] array的内容了。

      将字节数组流(字符串类型)转换为blob对象的功能:

      var b64toBlob = function(b64Data, contentType, sliceSize) {
            contentType = contentType || '';
            sliceSize = sliceSize || 512;
      
            var byteCharacters = atob(b64Data);
            var byteArrays = [];
      
            for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
              var slice = byteCharacters.slice(offset, offset + sliceSize);
      
              var byteNumbers = new Array(slice.length);
              for (var i = 0; i < slice.length; i++) {
                byteNumbers[i] = slice.charCodeAt(i);
              }
      
              var byteArray = new Uint8Array(byteNumbers);
      
              byteArrays.push(byteArray);
            }
      
            var blob = new Blob(byteArrays, {type: contentType});
            return blob;
      };
      

      这就是我调用此函数并使用 FileSaver.js 保存 blob 对象的方式(通过 Angular.js $http.get 获取数据):

          $http.get("your/api/uri").success(function(data, status, headers, config) {
              //Here, data is type of string
              var blob = b64toBlob(data, 'application/zip');
              var fileName = "download.zip";
              saveAs(blob, fileName);
          });
      

      注意:我发送byte[] array(Java-Server-Side)是这样的:

      byte[] myByteArray = /*generate your zip file and convert into byte array*/ new byte[]();
      return new ResponseEntity<byte[]>(myByteArray , headers, HttpStatus.OK);
      

      【讨论】:

        猜你喜欢
        • 2019-07-08
        • 1970-01-01
        • 2020-05-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-09-01
        相关资源
        最近更新 更多