使用MemoryStream和ZipArchive将zip文件返回到asp.net web api中的客户端

我试图使用以下代码将zip文件从asp.net web api返回给客户端:

private byte[] CreateZip(string data) { using (var ms = new MemoryStream()) { using (var ar = new ZipArchive(ms, ZipArchiveMode.Create, true)) { var file = archive.CreateEntry("file.html"); using (var entryStream = file.Open()) using (var sw = new StreamWriter(entryStream)) { sw .Write(value); } } return memoryStream.ToArray(); } } public HttpResponseMessage Post([FromBody] string data) { HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK); result.Content = new ByteArrayContent(CreateZip(data)); result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/zip, application/octet-stream"); return result; } 

当我运行此代码时,我收到以下错误:

ExceptionMessage“:”值’application / zip,application / octet-stream’的格式无效。“

这是JS代码:

 $.ajax({ type: "POST", url: url, data: data, dataType: application/x-www-form-urlencoded }); 

任何解释为什么会这样? 我真的很喜欢你的帮助人员

$.ajax处理文本响应并尝试(utf-8)解码内容:您的zip文件不是文本,您将获得损坏的内容。 jQuery不支持二进制内容,因此您需要使用此链接并在jQuery上添加ajax传输或直接使用XmlHttpRequest。 使用xhr,您需要设置xhr.responseType = "blob"并从xhr.response读取blob。

 // 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: 

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

 $.ajax({ url: url, type: "POST", contentType: "application/json", dataType: "binary", // to use the binary transport // responseType:'blob', this is the default data: data, processData: false, success: function (blob) { // the result is a blob, we can trigger the download directly saveAs(blob, "example.zip"); } // [...] }); 

使用原始XMLHttpRequest,您可以看到这个问题,您只需要添加一个xhr.responseType = "blob"来获取blob。

我个人建议你在jQuery上使用ajax传输,这非常简单,你必须下载一个库,将它包含在项目中并写入: dataType: "binary".

这是API代码,使用DotNetZip( Ionic.Zip ):

  [HttpPost] public HttpResponseMessage ZipDocs([FromBody] string[] docs) { using (ZipFile zip = new ZipFile()) { //this code takes an array of documents' paths and Zip them zip.AddFiles(docs, false, ""); return ZipContentResult(zip); } } protected HttpResponseMessage ZipContentResult(ZipFile zipFile) { var pushStreamContent = new PushStreamContent((stream, content, context) => { zipFile.Save(stream); stream.Close(); }, "application/zip"); return new HttpResponseMessage(HttpStatusCode.OK) { Content = pushStreamContent }; } 

这是我的解决方案,对我有用

C#方面

 public IActionResult GetZip([FromBody] List documents) { List listOfDocuments = new List(); foreach (DocumentAndSourceDto doc in documents) listOfDocuments.Add(_documentService.GetDocumentWithServerPath(doc.Id)); using (var ms = new MemoryStream()) { using (var zipArchive = new ZipArchive(ms, ZipArchiveMode.Create, true)) { foreach (var attachment in listOfDocuments) { var entry = zipArchive.CreateEntry(attachment.FileName); using (var fileStream = new FileStream(attachment.FilePath, FileMode.Open)) using (var entryStream = entry.Open()) { fileStream.CopyTo(entryStream); } } } ms.Position = 0; return File(ms.ToArray(), "application/zip"); } throw new ErrorException("Can't zip files"); } 

不要错过ms.Position = 0; 这里

正面 (角4):

 downloadZip(datas: any) { const headers = new Headers({ 'Content-Type': 'application/json', 'Accept': 'application/zip' }); const options = new RequestOptions({ headers: headers, withCredentials: true, responseType: ResponseContentType.ArrayBuffer }); const body = JSON.stringify(datas); return this.authHttp.post(`${environment.apiBaseUrl}api/documents/zip`, body, options) .map((response: Response) => { const blob = new Blob([response.blob()], { type: 'application/zip' }); FileSaver.saveAs(blob, 'logs.zip'); }) .catch(this.handleError); } 

现在我可以下载多个文件到zip。

传递给MediaTypeHeaderValue的构造函数的值的格式无效。 您还尝试将多种内容类型添加到标头值。

内容类型标题采用单个类型/子类型,后跟可选参数,以分号分隔;

例如:

 Content-Type: text/html; charset=ISO-8859-4 

对于您的结果,您需要决定要使用哪一个。 application/zipapplication/octet-stream

 result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/zip"); 

此外,为避免exception,您可以使用MediaTypeHeaderValue.TryParse方法

 var contentTypeString = "application/zip"; MediaTypeHeaderValue contentType = null; if(MediaTypeHeaderValue.TryParse(contentTypeString, out contentType)) { result.Content.Headers.ContentType = contentType; }