首页 > 解决方案 > 通过 jQuery 下载时 Zip 文件无效

问题描述

我正在开发一个 MVC 站点,以允许客户选择多个文档进行下载。我编写了允许他们单独生成任何交易的 PDF 的代码。新要求是允许选择行,然后生成一个包含所有生成的 PDF 的 zip 文件。

该网页在顶部设置了一个过滤器部分,之后表格中的事务和表格下方是分页控件。整个页面被包裹在一个表单中。由于我需要的数据已经在表格中,我将页面分成两种形式,一种用于过滤,一种用于下载。问题是分页控件是表单的一部分,需要过滤控件与页面一起提交。我将分页移到表格上方,这样它就可以成为过滤器表单的一部分,同时保留表格表单以用于我的多个 PDF 下载操作。这很好用,但我们有几个页面使用这种设置,所以为了保持网站统一,我必须将分页移动到所有这些页面的顶部。此外,营销对这种变化并不疯狂,但要了解这是否是必要的。

由于我无法在表单中嵌入表单,因此我决定为每一行的复选框添加属性,并使用 jQuery 遍历它们并提取我的操作所需的数据。这部分效果很好,我得到了我需要的所有数据,我把它们放到一个对象数组中,做 json 字符串化,我的控制器很高兴。我发现了这个问题:Download a file by jQuery.Ajax and try some answers。经过一些参数摆弄后,我让它返回二进制数据。我找到了一个解决方案,允许我的 ajax 调用下载它接收到的文件,并且看起来它正在工作,但是当我打开 zip 文件时,我得到“Windows 无法打开文件夹。压缩(压缩)文件夹 'c:\path\deliveries. zip' 无效”。

我知道该操作之前有效,因为它在连接为表单时有效,我只是在 _blank 目标上打开了表单操作。我应该提到我坚持使用 jQuery 1.11,因为这个应用程序很大,更新 jQuery 需要一周或更长时间来测试所有页面和功能。

这是控制器代码(工作正常)

[HttpPost]
public ActionResult GetMultiplePdfs(List<DeliveryPdfDownloadViewModel> deliveries)
{
    using (var memoryStream = new MemoryStream())
    {
        using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
        {
            foreach (var delivery in deliveries)
            {
                string file = $"Delivery-{delivery.CustomerNumber}-{delivery.siteNumber}-{delivery.Time.ToString("yyyyMMddhhmmss")}.pdf";
                var url = $"/api/Delivery?customerNumber={delivery.CustNum}&shipToNumber={delivery.ShipToNum}&startTime={delivery.StartTime}";
                var response = _client.GetAsync(url).GetAwaiter().GetResult();

                var pdf = archive.CreateEntry(file);
                using(var entryStream = pdf.Open())
                using(var streamWriter = new StreamWriter(entryStream, Encoding.UTF8))
                {
                    var byteArray = response.Content.ReadAsByteArrayAsync().GetAwaiter().GetResult();
                    streamWriter.BaseStream.Write(byteArray, 0, byteArray.Length);
                    streamWriter.Flush();
                }
            }
        }
        logger.Info($"Successfully created zip file with {deliveries.Count()} PDF documents in it");
        return File(memoryStream.ToArray(), "application/zip", "deliveries.zip");
    }
}

这是 jQuery

 $.ajax({
    url: "@Url.Action("GetMultiplePdfs")",
    type: "POST",
    //dataType: 'application/zip',
    data: { "deliveries": data },
    //xhrFields: {
    //    responseType: "blob"
    //},
    success: function (result) {
        let bobloblaw = new Blob([result]);
        let a = document.createElement('a');
        a.href = window.URL.createObjectURL(bobloblaw);
        a.download = "deliveries.zip";
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        window.URL.revokeObjectURL(a.href);
    },
    error: function () {
        alert("Unable to download PDFs")
    }
    });

    //subscribeRequest.done(function (data) {
    //    console.log(data);
    //});

我包括了一些我尝试过的注释掉的行。在我摆脱 contentType 之前,我的操作无法识别我发送的 json。我的 ajax 调用失败,直到我删除了 dataType;我尝试使用 subscribeRequest 而不是成功,但结果相同。我尝试将 ajax 调用中的 responseType 设置为 blob。在创建我的 Blob 时,我尝试了 { type: "application/zip" },我还尝试了从上面的链接中找到的 "application/octetstream"。

标签: jqueryasp.net-mvc

解决方案


我让它工作了。我找到了另一个问题:Recifying a Zip file as response on AJAX request

我尝试了以下代码,它成功了!!!

fetch("@Url.Action("GetMultiplePdfs")", {
    method: "POST",
    headers: {
        "content-type": "application/json"
    },
    body: JSON.stringify(data)
})
    .then((response) => {
        response.blob().then((blob) => {
            const downloadUrl = window.URL.createObjectURL(blob);
            const link = document.createElement('a');
            link.setAttribute('href', downloadUrl);
            link.setAttribute('download', 'file');
            link.style.display = 'none';
            document.body.appendChild(link);
            link.click();
            window.URL.revokeObjectURL(link.href);
            document.body.removeChild(link);
        })
    });

我不确定 fetch 和 ajax 之间有什么区别,但不知何故这正在返回我的文件。zip 文件打开,PDF 文件完好无损。


推荐阅读