web-dev-qa-db-fra.com

Obtenir le fichier Excel (.xlsx) de la réponse du serveur en ajax

J'ai un problème pour obtenir un fichier Excel et ouvrir la fenêtre de téléchargement dans le navigateur après avoir obtenu une réponse (avec la méthode ajax avec succès) avec ce fichier. J'ai eu le Content-Type and Content-Disposition headers approprié, j'ai essayé d'utiliser Blob en js et je ne pouvais pas atteindre ce que je voulais - le téléchargement de fichier simple.
J'ai réalisé quelques versions de mon ajax, l’une d’elles est en dessous. J'ai développé ajax qui renvoie un fichier Excel que je ne pouvais pas ouvrir correctement car il est corrompu (malgré l'extension .xlsx). 

Peut-être que le problème est avec le type de données inapproprié utilisé dans le constructeur Blob? 

J'ai essayé d'utiliser "xhr.response" au lieu de "données" à partir d'arguments de méthode de réussite, mais cela ne fonctionne pas trop. J'ai vérifié les en-têtes de réponse dans les outils de développement de Chrome et ils sont correctement définis.
La chose importante: tous les classeurs Excel créés côté serveur sont corrects car ils fonctionnaient dans la version précédente lorsque les données étaient envoyées dans une URL, et non dans une publication ajax.

Méthode du contrôleur côté serveur Java/Spring ci-dessous:

response.reset();
response.setContentType("application/vnd.ms-Excel");
response.addHeader("Content-Disposition","attachment;filename=\"" + className + " " +  title + ".xlsx\"");
    try (ServletOutputStream output = response.getOutputStream()){
        workbook.write(output);
        output.flush();
    } catch (Exception e) {
        throw new RuntimeException(e);
    }

Mon Ajax pour télécharger le fichier et ouvrir la fenêtre de téléchargement:

$.ajax({
    url: myUrl,
    type: 'POST',
    data: myData,
    success: function(data, status, xhr) {
        var contentType = 'application/vnd.ms-Excel';

        var filename = "";
        var disposition = xhr.getResponseHeader('Content-Disposition');
        if (disposition && disposition.indexOf('attachment') !== -1) {
            var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
            var matches = filenameRegex.exec(disposition);
            if (matches != null && matches[1]) filename = matches[1].replace(/['"]/g, '');
        }
        console.log("FILENAME: " + filename);

        try {
            var blob = new Blob([data], { type: contentType });

            var downloadUrl = URL.createObjectURL(blob);
            var a = document.createElement("a");
            a.href = downloadUrl;
            a.download = filename;
            document.body.appendChild(a);
            a.click();

        } catch (exc) {
            console.log("Save Blob method failed with the following exception.");
            console.log(exc);
        }
4
KamilosD

Il semble que JQuery rencontre un problème avec le traitement des données binaires de la réponse. J'ai simplement utilisé XMLHttpRequest et j'ajoute toutes les données à l'URL.

var request = new XMLHttpRequest();
request.open('POST', url, true);
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
request.responseType = 'blob';

request.onload = function(e) {
    if (this.status === 200) {
        var blob = this.response;
        if(window.navigator.msSaveOrOpenBlob) {
            window.navigator.msSaveBlob(blob, fileName);
        }
        else{
            var downloadLink = window.document.createElement('a');
            var contentTypeHeader = request.getResponseHeader("Content-Type");
            downloadLink.href = window.URL.createObjectURL(new Blob([blob], { type: contentTypeHeader }));
            downloadLink.download = fileName;
            document.body.appendChild(downloadLink);
            downloadLink.click();
            document.body.removeChild(downloadLink);
           }
       }
   };
   request.send();
6
KamilosD

Nous avions absolument le même problème récemment. Pour nous, cela a commencé à fonctionner lorsque nous avons ajouté responseType: 'arraybuffer' aux paramètres ajax. Et il vaut mieux utiliser lib https://github.com/eligrey/FileSaver.js/ au lieu de cliquer manuellement sur le lien, car cet outil annule également la mémoire.

0