【问题标题】:Corrupted Zip while returning from Web API?从 Web API 返回时损坏的 Zip?
【发布时间】:2016-05-12 18:19:25
【问题描述】:

在我的 MVC 项目中,我有一个对 Web API 的 AJAX 调用。

我发送一组文档的路由,API(应该)压缩它们并返回压缩文件

self.zipDocs = function (docs, callback) {
    $.ajax({
        url: "../SharedAPI/documents/zip",
        type: "POST",
        data: docs,
        contentType: "application/json",
        success: function (data) {
            var zip = new JSZip(data);
            var content = zip.generate({ type: "blob" });
            saveAs(content, "example.zip");
        },
        error: function (data) {
            callback(data);
        }
    });
}

还有我在 WebAPI 上的 ZipDocs 函数(使用 DotNetZip 库):

[HttpPost]
    [Route("documents/zip")]
    public HttpResponseMessage ZipDocs([FromBody] string[] docs)
    {

        using (var zipFile = new ZipFile())
        {
            zipFile.AddFiles(docs, false, "");
            return ZipContentResult(zipFile);
        }
    }

    protected HttpResponseMessage ZipContentResult(ZipFile zipFile)
    {
        // inspired from http://stackoverflow.com/a/16171977/92756
        var pushStreamContent = new PushStreamContent((stream, content, context) =>
        {
           zipFile.Save(stream);
            stream.Close(); // After save we close the stream to signal that we are done writing.
        }, "application/zip");

        return new HttpResponseMessage(HttpStatusCode.OK) { Content = pushStreamContent };
    }

但是当 Zip 被返回时,我得到了以下错误:

未捕获的错误:损坏的 zip:缺少 16053 个字节。

真正奇怪的是,当我在 API 上将 zip 文件保存到磁盘时它被正确保存,我可以毫无问题地打开文件!

我做错了什么?我错过了什么吗? 请帮忙!

提前致谢。

【问题讨论】:

  • 我想知道您的zipFileusing 语句是否导致您的对象在数据实际保存到流中之前被释放。尝试删除 using 语句,看看它是否有效。在您的对象返回之前,您的保存代码不会运行。
  • 此时是否必须关闭流?你不是碰巧在所有东西都通过电线发送之前关闭它吗?

标签: c# ajax zip dotnetzip jszip


【解决方案1】:

两件事:

1/ $.ajax 处理文本响应并尝试 (utf-8) 解码内容:您的 zip 文件不是文本,您将获得损坏的内容。 jQuery doesn't support binary content 所以你需要使用前面的链接并在 jQuery 上添加一个 ajax 传输或直接使用 XmlHttpRequest。使用 xhr,您需要设置 xhr.responseType = "blob" 并从 xhr.response 读取 blob。

2/ 假设您的 js 代码 sn-p 是整个函数,您(尝试)获取二进制内容,解析 zip 文件,重新生成它,将内容提供给用户。你可以直接给出结果:

// with xhr.responseType = "arraybuffer"
var arraybuffer = xhr.response;
var blob = new Blob([arraybuffer], {type:"application/zip"});
saveAs(blob, "example.zip");

// with xhr.responseType = "blob"
var blob = xhr.response;
saveAs(blob, "example.zip");

编辑:示例:

使用jquery.binarytransport.js(任何可以让您下载 Blob 或 ArrayBuffer 的库都可以)

$.ajax({
  url: "../SharedAPI/documents/zip",
  dataType: 'binary', // to use the binary transport
  // responseType:'blob', this is the default
  // [...]
  success: function (blob) {
    // the result is a blob, we can trigger the download directly
    saveAs(blob, "example.zip");
  }
  // [...]
});

使用原始 XMLHttpRequest,你可以看到这个question,你只需要添加一个xhr.responseType = "blob" 来获得一个 blob。

我从未使用过 C#,但据我所知,[FromBody] 对数据格式非常敏感,在您的情况下,第一个解决方案应该更容易实现。

【讨论】:

  • 感谢您的回答,我明白您的意思,但不太确定该怎么做,我必须在我的 Web API 上使用 xhr 吗?还是仅在返回数据时?你能指导我吗?抱歉这个愚蠢的问题,但我对这个不太熟悉......谢谢!
  • xhr 将替换这个 $.ajax 调用。最简单的解决方案是使用额外的 ajax 传输,因为它只需要添加一个库并使用dataType: 'binary'。我已经更新了我的答案以包含一个示例。
  • 太棒了!!完美运行,对 AJAX 功能进行了一些小的编辑!我很想给你投票不止一次!非常感谢!!!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-12
  • 2012-11-20
  • 2019-02-18
  • 2020-06-23
  • 2016-12-07
相关资源
最近更新 更多