2016-05-12 6 views
2

In meinem MVC-Projekt habe ich einen AJAX-Aufruf an eine Web-API.Beschädigter Zip beim Zurückkehren von der Web-API?

Ich sende eine Reihe von Dokumenten Routen, die API (sollte) reißt sie und gibt die Zip-Datei zurück.

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

und Funktion meine ZipDocs auf dem WebAPI (die DotNetZip-Bibliothek):

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

Aber wenn das Zip zurückgegeben ich folgende Fehlermeldung bekommen:

Uncaught Error: Corrupted zip: missing 16053 bytes.

Was ist wirklich komisch, wenn ich auf der API die Zip-Datei auf der Festplatte speichern wird es richtig gespeichert und ich kann die Datei ohne Probleme öffnen!

Was mache ich falsch? Fehle ich etwas? Bitte helfen!

Vielen Dank im Voraus.

+0

Ich frage mich, ob Ihre 'using' Anweisung für die' zipFile' verursacht Ihr Objekt entsorgt werden, bevor die Daten tatsächlich in den Stream vollständig gespeichert werden. Versuchen Sie, die using-Anweisung zu entfernen und zu überprüfen, ob sie funktioniert. Ihr Sicherungscode wird erst nach der Rückgabe des Objekts ausgeführt. – TyCobb

+0

Müssen Sie den Stream an diesem Punkt schließen? Schliessen Sie es nicht, bevor alles über die Leitung gesendet wurde? –

Antwort

2

Zwei Dinge:

1/$.ajax Textantworten behandelt und wird versuchen, (utf-8) dekodieren den Inhalt: Ihre Zip-Datei nicht Text ist, werden Sie einen beschädigten Inhalte. jQuery doesn't support binary content, also müssen Sie den vorherigen Link verwenden und einen Ajax-Transport auf jQuery hinzufügen oder direkt ein XmlHttpRequest verwenden. Mit einer Xhr müssen Sie xhr.responseType = "blob" setzen und von xhr.response den Blob lesen.

2/unter der Annahme, dass Ihr js Code-Snippet die ganze Funktion ist, versuchen Sie, einen binären Inhalt zu erhalten, die ZIP-Datei zu analysieren, neu zu generieren, den Inhalt dem Benutzer zu geben. Sie können direkt das Ergebnis geben:

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

mit jquery.binarytransport.js (jede Bibliothek, die Sie ein Blob lassen herunterladen oder ein Arraybuffer tun)

$.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"); 
    } 
    // [...] 
}); 

mit einem rohe XMLHttpRequest, können Sie diese question sehen, müssen Sie nur eine xhr.responseType = "blob" hinzufügen, um einen Blob zu erhalten.

Ich habe nie C# verwendet, aber von was ich sehen kann, ist [FromBody] ziemlich empfindlich auf das Format der Daten, sollte die erste Lösung in Ihrem Fall einfacher zu implementieren sein.

+0

Vielen Dank für Ihre Antwort, ich verstehe, was Sie sagen, aber nicht wirklich sicher, wie es geht, muss ich xhr bereits auf meiner Web-API verwenden? oder nur wenn die Daten zurückgegeben werden? Könntest du mich führen? Sorry für die dumme Frage, aber ich bin nicht so vertraut mit ... Danke! – user3378165

+1

Die xhr würde diesen $ .ajax Aufruf ersetzen. Die einfachste Lösung besteht darin, den zusätzlichen Ajax-Transport zu verwenden, da nur eine Bibliothek hinzugefügt und 'dataType: 'binary'' verwendet werden muss. Ich habe meine Antwort aktualisiert, um ein Beispiel hinzuzufügen. –

+0

ERSTAUNLICH !! Perfekt funktioniert, mit ein paar kleinen Änderungen an der AJAX-Funktion! Ich würde dich gerne mehr als einmal wählen! Ich danke dir sehr!!! – user3378165

Verwandte Themen