web-dev-qa-db-fra.com

Téléchargement client d'un fichier Zip généré par le serveur

Avant que quelqu'un dise, "dupliquer", je veux juste m'assurer, que les gens sachent, que j'ai déjà examiné ces questions:

1) Utilise angular et php, je ne sais pas ce qui se passe ici (je ne connais pas PHP): Téléchargez le fichier Zip et déclenchez le dialogue "Enregistrer le fichier" à partir de la méthode angulaire

2) Vous ne pouvez pas obtenir cette réponse pour faire quoi que ce soit: comment télécharger un fichier Zip avec angular

3) Cette personne peut déjà télécharger, ce qui est dépassé par le problème que j'essaie de comprendre: Télécharger un fichier Zip externe à partir d’un angle déclenché par une action sur un bouton

4) Pas de réponse pour celui-ci: télécharger le fichier .Zip du serveur dans nodejs

5) Je ne sais pas de quelle langue il s'agit: https://stackoverflow.com/questions/35596764/Zip-file-download-using-angularjs-directive

Etant donné ces questions , s'il s'agit toujours d'un doublon, je m'en excuse. Voici encore une autre version de cette question.

Mon client 1.5.X angulaire me fournit une liste de titres, chacun ayant un fichier associé. Mon serveur 4.X/Express 4.X utilise cette liste, récupère les emplacements des fichiers, crée un fichier Zip à l'aide de la méthode express-Zip de npm, puis transfère ce fichier dans la réponse. Je souhaite ensuite que mon client lance l'option "télécharger un fichier" du navigateur. 

Voici mon code client (Angular 1.5.X):

function bulkdownload(titles){
    titles = titles || [];
    if ( titles.length > 0 ) {
        $http.get('/query/bulkdownload',{
            params:{titles:titles},
            responseType:'arraybuffer'
        })
        .then(successCb,errorCb)
        .catch(exceptionCb);
    }

    function successCb(response){
        // This is the part I believe I cannot get to work, my code snippet is below
    };

    function errorCb(error){
            alert('Error: ' + JSON.stringify(error));
    };

    function exceptionCb(ex){
            alert('Exception: ' + JSON.stringify(ex));
    };
};

Node (4.X) code avec express-Zip, https://www.npmjs.com/package/express-Zip :

router.get('/bulkdownload',function(req,resp){
    var titles = req.query.titles || [];

    if ( titles.length > 0 ){
        utils.getFileLocations(titles).
        then(function(files){
            let filename = 'zipfile.Zip';

            // .Zip sets Content-Type and Content-disposition
            resp.Zip(files,filename,console.log);
        },
        _errorCb)
    }
});

Voici mon successCb dans mon code client (Angular 1.5.X):

function successCb(response){
    var URL = $window.URL || $window.webkitURL || $window.mozURL || $window.msURL;
    if ( URL ) {
        var blob = new Blob([response.data],{type:'application/Zip'});
        var url = URL.createObjectURL(blob);
        $window.open(url);
    }
};

La partie "blob" semble fonctionner correctement. En le vérifiant dans le débogueur d'IE, cela ressemble à un flux de fichiers contenant des informations sur les octets. Maintenant, je crois que je dois insérer ce blob dans la directive HTML5 pour lancer le "Enregistrer le fichier sous" à partir du navigateur. Peut être? Peut être pas?

Puisque plus de 90% de nos utilisateurs utilisent IE11, je teste tous mes angles dans PhantomJS (Karma) et IE. Lorsque j'exécute le code, le message d'erreur «Accès refusé» s'affiche dans une fenêtre d'alerte:

Exception: {"description":"Access is denied...<stack trace>}

Les suggestions, clarifications, réponses, etc. sont les bienvenues!

5
westandy

J'ai mis à jour ma méthode bulkdownload pour utiliser $window.open(...) au lieu de $http.get(...):

function bulkdownload(titles){
    titles = titles || [];
    if ( titles.length > 0 ) {
        var url = '/query/bulkdownload?';
        var len = titles.length;
        for ( var ii = 0; ii < len; ii++ ) {
            url = url + 'titles=' + titles[ii];
            if ( ii < len-1 ) {
                url = url + '&';
            }
        }
        $window.open(url);
    }
};

Je l'ai seulement testé dans IE11. 

1
westandy
var Zip_file_path = "" //put inside "" your path with file.Zip
var Zip_file_name = "" //put inside "" file name or something
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
a.href = Zip_file_path;
a.download = Zip_file_name;
a.click();
document.body.removeChild(a);
4
atom

Utilisez celui-ci:

var url="YOUR Zip URL HERE";
window.open(url, '_blank');
1
Chinmay235

Comme indiqué dans cette réponse , j’ai utilisé la fonction Javascript ci-dessous et je peux maintenant télécharger le contenu byte[] array avec succès.

Fonction permettant de convertir un flux de tableau d'octets (type de chaîne) en objet blob:

var b64toBlob = function(b64Data, contentType, sliceSize) {
      contentType = contentType || '';
      sliceSize = sliceSize || 512;

      var byteCharacters = atob(b64Data);
      var byteArrays = [];

      for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
        var slice = byteCharacters.slice(offset, offset + sliceSize);

        var byteNumbers = new Array(slice.length);
        for (var i = 0; i < slice.length; i++) {
          byteNumbers[i] = slice.charCodeAt(i);
        }

        var byteArray = new Uint8Array(byteNumbers);

        byteArrays.Push(byteArray);
      }

      var blob = new Blob(byteArrays, {type: contentType});
      return blob;
};

Voici comment j'appelle cette fonction et enregistre l'objet blob avec FileSaver.js (obtenir des données via Angular.js $http.get):

    $http.get("your/api/uri").success(function(data, status, headers, config) {
        //Here, data is type of string
        var blob = b64toBlob(data, 'application/Zip');
        var fileName = "download.Zip";
        saveAs(blob, fileName);
    });

Remarque: J'envoie le byte[] array (côté serveur Java) comme ceci:

byte[] myByteArray = /*generate your Zip file and convert into byte array*/ new byte[]();
return new ResponseEntity<byte[]>(myByteArray , headers, HttpStatus.OK);
0
Bahadir Tasdemir