如何在JavaScript中保存zip文件的二进制数据?

38

我从AJAX响应中得到以下反馈:

这是zip文件的响应。 请告诉我如何在Javascript中保存此文件名为filename.zip。ZIP文件中包含PDF文件。

我的代码如下:

$.ajax({

    url: baseURLDownload + "/service/report-builder/generateReportContentPDF",
    beforeSend: function (xhr) {
        xhr.setRequestHeader("Access-Control-Allow-Origin", "*");
        xhr.responseType = 'arraybuffer'
    },
    type: "POST",
    data: JSON.stringify(parameter),
    contentType: "application/json",
    success: function(result) {
        console.log("ssss->"+result);
        var base64String = utf8_to_b64(result);
        //window.open("data:application/zip;base64,"+base64String); // It will download pdf in zip
        var zip = new JSZip();
        zip.add("PDFReport.pdf", result);
        content = zip.generate();
        location.href="data:application/zip;base64," + content;
        $.mobile.loading('hide');

    },
    error: function(xhr){
        console.log("Request Status: " + xhr.status + " Status Text: " + xhr.statusText + " " + xhr.responseText);
        $.mobile.loading('hide');
        showAlert("Error occured. Unable to download Report", "Message", "OK");

    }
});

RESPOSE Console.log("ssss->"+result);


什么问题? - Robert Harvey
请帮我编写代码,我该如何将这个二进制数据保存为文件。这是我得到的响应。 - Nishant Singh
解决方案:https://dev59.com/M4nca4cB1Zd3GeqP_nzi#29518340 - MeGoodGuy
5个回答

36

最终我得到了我的问题的答案:

这是代码:

var xhr = new XMLHttpRequest();
xhr.open("POST", baseURLDownload + "/service/report/QCPReport", true);
xhr.setRequestHeader("Content-type","application/json");
xhr.setRequestHeader("Access-Control-Allow-Origin", "*");
xhr.onreadystatechange = function() {
    if (xhr.readyState == 4 && xhr.status == 200) {
        // alert("Failed to download:" + xhr.status + "---" + xhr.statusText);
        var blob = new Blob([xhr.response], {type: "octet/stream"});
        var fileName = "QCPReport.zip";
        saveAs(blob, fileName);
    }
}
xhr.responseType = "arraybuffer";
xhr.send(JSON.stringify(QCPParameter));

11
谢谢。 "xhr.responseType =“arraybuffer”; "是我之前漏掉的部分。 - ulab
一样的情况。不过在我这里(稍微不同的代码),我需要将类型设置为“application/zip”。 - Michael Zlatkovsky - Microsoft
任何帮助都是受欢迎的。类似的问题请参考https://stackoverflow.com/a/53274895/1257574 - Harvey Dent
谢谢!这真是拯救了我的一命,试了很多方法最后只有这个起作用了。 - Dip Parmar
2
为什么不设置 xhr.responseType = "blob",然后直接使用 xhr.response 呢? - Haibrayn González
在axios中使用axios.get(url, {responseType: 'arraybuffer'}) - nlavr

16

Axios 实现:

const url = 'https://www.example.com/download-zip'

// Payload, eg list of docs to zip
const payload = { documents: ['id1', 'id2', 'id3'] }

// Axios options
const axiosOptions = {
  responseType: 'arraybuffer',
  headers: {
    'Content-Type': 'application/json'
  }
}

// Fetch data and save file
axios
  .post(url, payload, axiosOptions)
  .then((response) => {
    const blob = new Blob([response.data], {
      type: 'application/octet-stream'
    })
    const filename = 'download.zip'
    saveAs(blob, filename)
  })
  .catch((e) => {
    // Handle error
  })
})

注意

saveAs是一个来自file-saver包的函数,我一直在使用它来处理文件保存。


1
saveAs函数来自哪里? - Ashwin
1
@Ashwin 无论是助手函数还是用于保存文件的包实现,最有可能我使用了file-saver:https://www.npmjs.com/package/file-saver - ego
3
响应类型:缓冲区非常重要。 - hafiz ali
这也适用于GET请求,以防有人想知道。POST不是必需的。 - Onur Çevik

13

无依赖。

兼容IE 10、11、Chrome、FF和Safari:

function str2bytes (str) {
   var bytes = new Uint8Array(str.length);
   for (var i=0; i<str.length; i++) {
      bytes[i] = str.charCodeAt(i);
    }
    return bytes;
}

var xhr = new XMLHttpRequest();
xhr.open("POST", baseURLDownload + "/service/report/QCPReport", true);
xhr.setRequestHeader("Content-type","application/json");
xhr.setRequestHeader("Access-Control-Allow-Origin", "*");
xhr.onreadystatechange = function() {
    if (xhr.readyState == 4 && xhr.status == 200) {
        // alert("Failed to download:" + xhr.status + "---" + xhr.statusText);
        var blob = new Blob([str2bytes(xhr.response)], {type: "application/zip"});
        var fileName = "QCPReport.zip";
        if (navigator.msSaveOrOpenBlob) {
            navigator.msSaveOrOpenBlob(blob, filename);
        } else {
            var a = document.createElement("a");
            document.body.appendChild(a);
            a.style = "display:none";
            var url = window.URL.createObjectURL(blob);
            a.href = url;
            a.download = filename;
            a.click();
            window.URL.revokeObjectURL(url);
            a.remove();
        }
    }
}
xhr.responseType = "arraybuffer";
xhr.send(JSON.stringify(QCPParameter));

1
这对我有用,谢谢!我只需要删除对str2bytes函数的调用。 - Xar

2
如果您正在使用fetch,您可以通过以下方式执行此操作。
fetch(url, config).
  .then((response) => {
    return response.arrayBuffer()
  })
  .then((data) => handleData(data))

在handleData函数中,你将实例化Blob对象来处理zip数据。

请问您能否扩展handleData函数的流程?它应该如何处理要下载的blob的实例化? - Melwyn Jensen

0

这是我的答案 您可以避免使用blob和Filesaver。

这是我为我的一个项目使用GET方法编写的方式。

var xmlHttp = new XMLHttpRequest();
xmlHttp.open("GET", url, true);
xmlHttp.setRequestHeader("Content-type","application/json");
xmlHttp.setRequestHeader("Access-Control-Allow-Origin", "*");
xmlHttp.responseType= 'blob';

xmlHttp.onreadystatechange = function() {
    if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
        const downloadUrl = window.URL.createObjectURL(xmlHttp.response);
        const link = document.createElement('a');
        link.setAttribute('href', downloadUrl);
        link.setAttribute('download', `filename.zip`);
        link.style.display = 'none';
        document.body.appendChild(link);
        link.click();
        window.URL.revokeObjectURL(link.href);
        document.body.removeChild(link);
    }
}
xmlHttp.responseType = "arraybuffer";
xmlHttp.send();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接