【问题标题】:How to download a byte array as a zip file in an AngularJS client?如何在 AngularJS 客户端中将字节数组下载为 zip 文件?
【发布时间】:2019-07-13 19:16:57
【问题描述】:

我敢肯定,多年来,这个问题和类似的变体已经在这里被问过很多次了。我已经经历了几乎所有事情,但仍然无法正确执行。

我有一个 .NET Core API 端点,它返回一个表示 zip 文件的字节数组:

    [HttpGet]
    [Route("download/{fileId}/")]
    public byte[] Download(long fileId)
    {
        ...
    }

我使用 AngularJS 的 $http 服务和 arraybuffer 作为 responseType 来发起请求:

    // AngularJS service (fileApiService)

    this.downloadFile = function (fileId) {
        var url = apiUrl + 'download/' + fileId;
        return $http.get(url, { responseType: 'arraybuffer' });
    };

我得到一个有效的响应,它的处理方式如下。我使用FileSaver.js 来访问saveAs 方法和Blob 构造函数:

    // AngularJS controller

    fileApiService.downloadFile(fileId)
        .then(function (response) {
           var data = response.data;
           var blob = new Blob([data], { type: 'application/octet-stream' });

           FileSaver.saveAs(blob, 'file.zip');   
        })
        .catch(function () {
            ...
        });

不幸的是,无论我对上述代码进行什么调整,这都会导致存档文件损坏。 Window 10 zip 实用程序抱怨即使文件不为空,也无法打开存档。我尝试了以下方法:

  • $http.get() 请求中将responseType 设置为blob 并直接将其传递给FileSaver.saveAs() 方法
  • application/zip 和其他 MIME 类型传递给 Blob 构造函数
  • { autoBOM: true } 传递给FileSaver.saveAs() 方法

我怀疑这是一个编码问题,因为另一个 ASP.NET Web 窗体应用程序可以从同一个 API 端点下载有效的 zip 文件。

任何指针将不胜感激。提前致谢!

【问题讨论】:

    标签: angularjs blob angular-http arraybuffer filesaver.js


    【解决方案1】:

    试试这个

    fileApiService.downloadFile(fileId)
    .then(function (response) {
        var data = response.data;
    
        function b64toBlob(b64Data, contentType, sliceSize) {
            contentType = contentType || '';
            sliceSize = sliceSize || 512; // sliceSize represent the bytes to be process in each batch(loop), 512 bytes seems to be the ideal slice size for the performance wise 
    
            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;
        }
    
        var blob = b64toBlob(data, 'application/octet-stream');
    
        FileSaver.saveAs(blob, 'file.zip');
    })
    .catch(function () {
        // ...
    });
    

    希望这会有所帮助。

    【讨论】:

    • 我之前尝试过使用 atob() 的解决方案,现在尝试使用您的解决方案。我得到这个:“无法在'Window'上执行'atob':要解码的字符串未正确编码”
    • 我还可以看到响应末尾有一些'='字符。我猜这意味着base64内容中有一些填充并且字符串是完整的
    • 呃,刚刚注意到你的 response.data 是字节数组。您可以尝试从 new Blob([data], { type: 'application/octet-stream' }); 更改代码吗? to new Blob([new Uint8Array(data)], { type: 'application/octet-stream' });
    • 那也没用。它仍然会下载无效的存档!
    • 从 $http.get() 请求中删除 responseType: 'arraybuffer' 后,我尝试了您的原始解决方案,并且成功了!你觉得是什么原因?
    猜你喜欢
    • 1970-01-01
    • 2014-10-10
    • 2020-05-23
    • 1970-01-01
    • 2012-01-12
    • 2016-01-12
    • 2020-11-08
    • 1970-01-01
    相关资源
    最近更新 更多