I'm sure this question and similar variants have been asked many times here over the years. I've gone through almost everything and am still unable to execute this properly.
I've a .NET Core API endpoint that returns a byte array that represents a zip file:
[HttpGet]
[Route("download/{fileId}/")]
public byte[] Download(long fileId)
{
...
}
I use AngularJS's $http
service with arraybuffer
as the responseType
to initiate a request:
// AngularJS service (fileApiService)
this.downloadFile = function (fileId) {
var url = apiUrl + 'download/' + fileId;
return $http.get(url, { responseType: 'arraybuffer' });
};
I get a valid response and it's handled like below. I use FileSaver.js to access the saveAs
method and the Blob
constructor:
// 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 () {
...
});
Unfortunately this results in a corrupted archive file regardless of whatever tweak I do to the above code. The Window 10 zip utility complains that the archive cannot be opened even if the file is not empty. I've tried the following:
responseType
as blob
in the $http.get()
request and directly passing that into FileSaver.saveAs()
methodapplication/zip
and other MIME types to the Blob
constructor{ autoBOM: true }
to the FileSaver.saveAs()
methodI'm suspecting that this is an encoding issue as another ASP.NET Web Forms application can download a valid zip file from the same API endpoint.
Any pointers would be greatly appreciated. Thanks in advance!
Try this
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 () {
// ...
});
Hope this helps.