【问题标题】:MVC Web Api + ajax to create and download Zip FileMVC Web Api + ajax 创建和下载 Zip 文件
【发布时间】:2020-09-19 00:59:28
【问题描述】:

我正在开发一个具有按钮的应用程序,当单击该按钮时,它会调用 Web api GET 方法。此方法获取文件并使用 System.IO.Compression 创建一个 zip 文件夹。这部分效果很好。我看到了它创建的文件夹,并且能够打开/提取该文件夹及其文件。我遇到的问题是当文件返回到浏览器并且浏览器下载文件时出现以下错误:“压缩(压缩)文件夹'...pathToTheDownloadedFile.zip'无效。我不明白我在做什么我做错了。所有其他非压缩文件下载并打开正常。

这是我的 web api GET 方法:

[HttpGet]
[Route("api/OrderManager/ExtractAllDocuments/{orderNum}/{mappingId}/")]
public HttpResponseMessage ExtractAllDocuments(int orderNum, int mappingId)
{
    try
    {
        var docPath = @"" + HttpContext.Current.Server.MapPath("MyPath");
        var files = Directory.GetFiles(docPath);
        string zipName = @"supportingdocuments_order" + orderNum + ".zip";

        FileStream zipToOpen = new FileStream(docPath + zipName, FileMode.Create);

        using (var zipArchive = new ZipArchive(zipToOpen, ZipArchiveMode.Create))
        {
            foreach (var fPath in files)
            {
                if (!fPath.Contains(".zip"))
                {
                    zipArchive.CreateEntryFromFile(fPath, Path.GetFileName(fPath), CompressionLevel.Fastest);
                }
            }
        }
        zipToOpen.Close();
        //At this point the directory is created and saved as it should be

        HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK);
        var fullZipPath = docPath + zipName;

        byte[] bytes = File.ReadAllBytes(fullZipPath);

        response.Content = new ByteArrayContent(bytes);
        response.Content.Headers.ContentLength = bytes.LongLength;
        response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
        response.Content.Headers.ContentDisposition.FileName = zipName;
        response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(MimeMapping.GetMimeMapping(zipName));


        return response;
    }
    catch (Exception e)
    {
        var b = e.Message;
        HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.NotFound);
        response.ReasonPhrase = string.Format("Failed To Extract Files");
        throw new HttpResponseException(response);
    }
}

这是我的 $.ajax 调用:

$.ajax({
    url: 'myApiUrl',
    method: 'GET'
}).done(function (data, status, xmlHeaderRequest) {
    var downloadLink = document.createElement('a');
    var blob = new Blob([data],
        {
            type: xmlHeaderRequest.getResponseHeader('Content-Type')
        });
    var url = window.URL || window.webkitURL;
    var downloadUrl = url.createObjectURL(blob);
    var fileName = '';

    // get the file name from the content disposition
    var disposition = xmlHeaderRequest.getResponseHeader('Content-Disposition');
    if (disposition && disposition.indexOf('attachment') !== -1) {
        var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
        var matches = filenameRegex.exec(disposition);
        if (matches != null && matches[1]) {
            fileName = matches[1].replace(/['"]/g, '');
        }
    }

    // Blob download logic taken from: https://stackoverflow.com/questions/16086162/handle-file-download-from-ajax-post
    if (typeof window.navigator.msSaveBlob !== 'undefined') {
        // IE workaround for "HTML7007" and "Access Denied" error.
        window.navigator.msSaveBlob(blob, fileName);
    } else {
        if (fileName) {
            if (typeof downloadLink.download === 'undefined') {
                window.location = downloadUrl;
            } else {
                downloadLink.href = downloadUrl;
                downloadLink.download = fileName;
                document.body.appendChild(downloadLink);
                downloadLink.click();
            }
        } else {
            window.location = downloadUrl;
        }

        setTimeout(function () {
            url.revokeObjectURL(downloadUrl);
        },
            100);
    }

}).fail(function (data) {
    $.notify({
        // options
        message:
            '<i class="fas fa-exclamation-circle"></i> Could not download all documents.'
    },
        {
            // settings
            type: 'danger',
            placement: {
                from: "top",
                align: "left"
            },
            delay: 2500,
            z_index: 10031
        });

});

我完全失去了这个。提前感谢您提供的任何帮助,非常感谢。

【问题讨论】:

  • 查看它创建的 zip 文件以查看实际输出的内容会很有趣。您可以对可以公开共享的文件执行此操作,以便我查看吗?或者对前 1000 个字节进行十六进制转储并将其粘贴到您的问题中
  • 是的,目前它只是一个空白的 .txt 文件。如何添加 zip 文件供您查看?
  • 这里是两个 zip 文件的链接,有效期至 9 月 20 日sendanywhe.re/5IW6NJ01
  • 谢谢 - 所以您的数据被编码为 UTF-8。我在其他地方看到过这个。实际上回答了一些关于它的事情。我们从来没有弄清楚是什么原因造成的:stackoverflow.com/questions/63229471/…
  • 为了好玩,你想试试这个答案吗? stackoverflow.com/questions/23568098/… 除了不要使用application/pdf,使用application/zip。我对content-disposition 部分感兴趣(使用inline 而不是attachment

标签: c# asp.net-mvc asp.net-web-api


【解决方案1】:

所以经过搜索,我找到了一个可行的解决方案。 $.ajax 不喜欢二进制数据,显然认为一切都是 UTF-8 文本编码。所以我使用了 XMLHttpRequest (xhr)。对于那些需要它的人,下面是 c# 和 javascript 解决方案的副本。

C# WebApi 控制器:

public HttpResponseMessage ExtractAllDocuments(int orderNum, int mappingId)
    {
        try
        {
            

            var docPath = @"" + HttpContext.Current.Server.MapPath("myPath");
            var files = Directory.GetFiles(docPath);
            string zipName = @"Supporting-Documents-Order-" + orderNum + ".zip";

            FileStream zipToOpen = new FileStream(docPath + zipName, FileMode.Create);

            using (var zipArchive = new ZipArchive(zipToOpen, ZipArchiveMode.Create))
            {
                foreach (var fPath in files)
                {
                    if (!fPath.Contains(".zip"))
                    {
                        zipArchive.CreateEntryFromFile(fPath, Path.GetFileName(fPath), CompressionLevel.Fastest);
                    }
                }
            }
            zipToOpen.Close();
            HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
            response.Content = new StreamContent(new FileStream(docPath + zipName, FileMode.Open, FileAccess.Read));
            response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
            response.Content.Headers.ContentDisposition.FileName = zipName;
            response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/zip");                               

            return response;
        }
        catch (Exception e)
        {
            var b = e.Message;
            HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.NotFound);
            response.ReasonPhrase = string.Format("Failed To Extract Files");
            throw new HttpResponseException(response);
        }
    }

前端 JavaScript:

function extractAllDocuments() {

        let xhr = new XMLHttpRequest();

        xhr.addEventListener('readystatechange', function (e) {
            if (xhr.readyState == 2 && xhr.status == 200) {
                // Download is being started
            }
            else if (xhr.readyState == 3) {
                // Download is under progress
            }
            else if (xhr.readyState == 4) {
                //operation done

                // Create a new Blob object using the response data of the onload object
                var blob = new Blob([this.response], { type: 'application/zip' });
                //Create a link element, hide it, direct it towards the blob, and then 'click' it programatically
                let a = document.createElement("a");
                a.style = "display: none";
                document.body.appendChild(a);
                //Create a DOMString representing the blob and point the link element towards it
                let url = window.URL.createObjectURL(blob);
                a.href = url;
                // get the file name from the content disposition
                var fileName = '';
                var disposition = xhr.getResponseHeader('Content-Disposition');
                if (disposition && disposition.indexOf('attachment') !== -1) {
                    var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
                    var matches = filenameRegex.exec(disposition);
                    if (matches != null && matches[1]) {
                        fileName = matches[1].replace(/['"]/g, '');
                    }
                }
                a.download = fileName;
                //programatically click the link to trigger the download
                a.click();
               
                //Remove From Server
                $.ajax({
                    url: 'myUrl',
                    method: 'DELETE'
                }).done(function (data) {

                }).fail(function (data) {

                });
                setTimeout(function () {
                    window.URL.revokeObjectURL(url);
                }, 60 * 1000);
            } else if (xhr.status == 400){
                $.notify({
                    // options
                    message:
                        '<i class="fas fa-exclamation-circle"></i> Could not download all documents.'
                },
                    {
                        // settings
                        type: 'danger',
                        placement: {
                            from: "top",
                            align: "left"
                        },
                        delay: 2500,
                        z_index: 10031
                    });
            }
        });

        //set the request type to post and the destination url to '/convert'
        xhr.open('GET', 'MyUrl');
        //set the reponse type to blob since that's what we're expecting back
        xhr.responseType = 'blob';
        xhr.send();

        return false;
    }

【讨论】:

    猜你喜欢
    • 2014-10-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多