问题
On my MVC project I have an AJAX call to a Web API.
I send an array of documents' routes, the API (should) zips them and returns the zip file.
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);
}
});
}
And my ZipDocs function on the WebAPI (using the DotNetZip library):
[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 };
}
But when the Zip is returned I got the following error:
Uncaught Error: Corrupted zip: missing 16053 bytes.
What is really weird, when I save on the API the zip file to the disk it gets saved properly and I can open the file without any problem!
What am I doing wrong? am I missing something? Please help!
Thanks in advance.
回答1:
Two things:
1/ $.ajax
handles text responses and will try to (utf-8) decode the content: your zip file isn't text, you will get a corrupted content. jQuery doesn't support binary content so you need to use the previous link and add an ajax transport on jQuery or use directly a XmlHttpRequest. With an xhr, you need to set xhr.responseType = "blob"
and read from xhr.response
the blob.
2/ assuming your js code snippet is the whole function, you (try to) get a binary content, parse the zip file, re-generate it, give the content to the user. You can give directly the result:
// 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");
Edit: examples:
with jquery.binarytransport.js (any library that let you download a Blob or an ArrayBuffer will do)
$.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");
}
// [...]
});
with a raw XMLHttpRequest, you can see this question, you just need to add a xhr.responseType = "blob"
to get a blob.
I never used C# but from what I can see, [FromBody]
is quite sensitive to the format of the data, the first solution should be easier to implement in your case.
来源:https://stackoverflow.com/questions/37194639/corrupted-zip-while-returning-from-web-api