2016-05-12 138 views
2

在我的MVC項目中,我有一個AJAX調用Web API。從Web API返回時損壞的Zip?

我發送一個文件的路由數組,API(應該)將它們壓縮並返回zip文件

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); 
     } 
    }); 
} 

而且我ZipDocs上的WebAPI(使用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 }; 
    } 

但是,當返回郵編我得到了以下錯誤:

Uncaught Error: Corrupted zip: missing 16053 bytes.

什麼是真的奇怪的是,當我保存在API上的zip文件到磁盤它得到妥善保存,我可以打開文件沒有任何問題!

我在做什麼錯?我錯過了什麼嗎? 請幫忙!

在此先感謝。

+0

我想知道如果''使用''''zipFile'語句導致您的對象被丟棄之前,數據實際上被保存到流的一路。嘗試刪除使用語句,看看它是否工作。直到對象返回後,您的保存代碼纔會運行。 – TyCobb

+0

您是否必須在該點關閉流?在你通過電報發送完畢之前,你是否恰好關閉它? –

回答

2

兩件事情:

1/$.ajax處理文本的反應,並會嘗試(UTF-8)解碼的內容:您的zip文件不是文本文件,你會得到一個損壞的內容。 jQuery doesn't support binary content因此您需要使用上一個鏈接並在jQuery上添加ajax傳輸或直接使用XmlHttpRequest。用xhr,你需要設置xhr.responseType = "blob"並從xhr.response讀取blob。

2 /假設您的js代碼片段是整個函數,您(試圖)獲取二進制內容,解析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]對數據格式非常敏感,第一個解決方案應該更容易實現在你的情況。

+0

感謝您的回答,我瞭解您的意見,但不確定該如何操作,是否必須在我的Web API上使用xhr?或只是當數據返回?你能引導我嗎?對不起,這個愚蠢的問題,但我不熟悉這個......謝謝! – user3378165

+1

xhr會替換這個$ .ajax調用。最簡單的解決方案是使用額外的ajax傳輸,因爲它只需要添加一個庫並使用'dataType:'binary''。我已經更新了我的答案以包含一個示例。 –

+0

令人驚歎!完美工作,只需對AJAX功能進行一些編輯即可!我很樂意投你一票!非常感謝!!! – user3378165