Télécharger et ouvrir le fichier PDF en utilisant Ajax

j'ai une classe d'action qui génère un PDF. Le contentType est réglé de façon appropriée.

public class MyAction extends ActionSupport 
{
   public String execute() {
    ...
    ...
    File report = signedPdfExporter.generateReport(xyzData, props);

    inputStream = new FileInputStream(report);
    contentDisposition = "attachment="" + report.getName() + """;
    contentType = "application/pdf";
    return SUCCESS;
   }
}

Je l'appelle action par un appel Ajax. Je ne sais pas comment livrer ce flux au navigateur. J'ai essayé quelques trucs mais rien n'a marché.

$.ajax({
    type: "POST",
    url: url,
    data: wireIdList,
    cache: false,
    success: function(response)
    {
        alert('got response');
        window.open(response);
    },
    error: function (XMLHttpRequest, textStatus, errorThrown) 
    {
        alert('Error occurred while opening fax template' 
              + getAjaxErrorString(textStatus, errorThrown));
    }
});

ce qui précède donne l'erreur:

votre navigateur a envoyé une requête que ce serveur ne pouvait pas comprendre.

74
demandé sur Mike B. 2010-01-04 16:42:19

12 réponses

vous n'avez pas nécessairement besoin D'Ajax pour cela. Un simple lien <a> suffit si vous définissez content-disposition à attachment dans le code côté serveur. De cette façon, la page mère restera ouverte, si c'était votre principale préoccupation (pourquoi auriez-vous inutilement choisi Ajax pour cela autrement?). En plus, il n'y a aucun moyen de gérer ça de façon acynchrone. PDF n'est pas une donnée de caractère. C'est des données binaires. Tu ne peux pas faire des trucs comme $(element).load() . Vous voulez utiliser complètement nouvelle demande pour ceci. Pour cela <a href="pdfservlet/filename.pdf">pdf</a> est parfaitement adapté.

pour vous aider davantage avec le code côté serveur, vous aurez besoin d'en dire plus sur la langue utilisée et d'afficher un extrait des tentatives de code.

32
répondu BalusC 2010-01-04 14:15:21

Voici comment j'ai obtenu ce travail

$.ajax({
  url: '<URL_TO_FILE>',
  success: function(data) {
    var blob=new Blob([data]);
    var link=document.createElement('a');
    link.href=window.URL.createObjectURL(blob);
    link.download="<FILENAME_TO_SAVE_WITH_EXTENSION>";
    link.click();
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

mise à jour de la réponse en utilisant télécharger.js

$.ajax({
  url: '<URL_TO_FILE>',
  success: download.bind(true, "<FILENAME_TO_SAVE_WITH_EXTENSION>", "<FILE_MIME_TYPE>")
});
106
répondu Mayur Padshala 2018-09-21 19:47:46

je ne pense vraiment pas que l'une de ces réponses repéré le problème de l'affiche originale. Ils présument tous une requête GET alors que l'affiche essayait de poster des données et d'obtenir un téléchargement en réponse.

dans le cadre de la recherche de toute meilleure réponse, nous avons trouvé ce jQuery Plugin pour la demande Ajax-like file Downloads .

dans son "coeur" il crée une forme HTML "temporaire" contenant les données Données données en entrée Fields. Ce formulaire est annexé au document et affiché à L'URL désirée. Juste après, le formulaire est à nouveau supprimé:

jQuery('<form action="'+ url +'" method="'+ (method||'post') +'">'+inputs+'</form>')
    .appendTo('body').submit().remove()

Update la réponse de Mayur semble très prometteuse et très simple par rapport au plugin jQuery auquel j'ai fait référence.

29
répondu chiccodoro 2015-08-17 08:01:25

C'est comme ça que je résous ce problème.

La réponse de Jonathan Amend sur ce post m'a beaucoup aidé.

L'exemple ci-dessous est simplifiée.

pour plus de détails, le code source ci-dessus est capable de télécharger un fichier en utilisant une requête Ajax JQuery (GET, POST, PUT etc) . Il, aussi, aide à télécharger des paramètres comme JSON et de changer le type de contenu à application/json (par défaut) .

The html source:

<form method="POST">
    <input type="text" name="startDate"/>
    <input type="text" name="endDate"/>
    <input type="text" name="startDate"/>
    <select name="reportTimeDetail">
        <option value="1">1</option>
    </select>
    <button type="submit"> Submit</button>
</form>  

une forme simple avec deux textes d'entrée, un select et un élément de bouton.

Le javascript de la page source:

<script type="text/javascript" src="JQuery 1.11.0 link"></script>
<script type="text/javascript">
    // File Download on form submition.
    $(document).on("ready", function(){
        $("form button").on("click", function (event) {
            event.stopPropagation(); // Do not propagate the event.

            // Create an object that will manage to download the file.
            new AjaxDownloadFile({
                url: "url that returns a file",
                data: JSON.stringify($("form").serializeObject())
            });

            return false; // Do not submit the form.
        });
    });
</script>  

un simple événement sur un clic de bouton. Il crée un objet AjaxDownloadFile. Le La classe AjaxDownloadFile source est ci-dessous.

Le AjaxDownloadFile classe source:

var AjaxDownloadFile = function (configurationSettings) {
    // Standard settings.
    this.settings = {
        // JQuery AJAX default attributes.
        url: "",
        type: "POST",
        headers: {
            "Content-Type": "application/json; charset=UTF-8"
        },
        data: {},
        // Custom events.
        onSuccessStart: function (response, status, xhr, self) {
        },
        onSuccessFinish: function (response, status, xhr, self, filename) {
        },
        onErrorOccured: function (response, status, xhr, self) {
        }
    };
    this.download = function () {
        var self = this;
        $.ajax({
            type: this.settings.type,
            url: this.settings.url,
            headers: this.settings.headers,
            data: this.settings.data,
            success: function (response, status, xhr) {
                // Start custom event.
                self.settings.onSuccessStart(response, status, xhr, self);

                // Check if a filename is existing on the response headers.
                var filename = "";
                var disposition = xhr.getResponseHeader("Content-Disposition");
                if (disposition && disposition.indexOf("attachment") !== -1) {
                    var filenameRegex = /filename[^;=\n]*=(([""]).*?|[^;\n]*)/;
                    var matches = filenameRegex.exec(disposition);
                    if (matches != null && matches[1])
                        filename = matches[1].replace(/[""]/g, "");
                }

                var type = xhr.getResponseHeader("Content-Type");
                var blob = new Blob([response], {type: type});

                if (typeof window.navigator.msSaveBlob !== "undefined") {
                    // IE workaround for "HTML7007: One or more blob URLs were revoked by closing the blob for which they were created. These URLs will no longer resolve as the data backing the URL has been freed.
                    window.navigator.msSaveBlob(blob, filename);
                } else {
                    var URL = window.URL || window.webkitURL;
                    var downloadUrl = URL.createObjectURL(blob);

                    if (filename) {
                        // Use HTML5 a[download] attribute to specify filename.
                        var a = document.createElement("a");
                        // Safari doesn"t support this yet.
                        if (typeof a.download === "undefined") {
                            window.location = downloadUrl;
                        } else {
                            a.href = downloadUrl;
                            a.download = filename;
                            document.body.appendChild(a);
                            a.click();
                        }
                    } else {
                        window.location = downloadUrl;
                    }

                    setTimeout(function () {
                        URL.revokeObjectURL(downloadUrl);
                    }, 100); // Cleanup
                }

                // Final custom event.
                self.settings.onSuccessFinish(response, status, xhr, self, filename);
            },
            error: function (response, status, xhr) {
                // Custom event to handle the error.
                self.settings.onErrorOccured(response, status, xhr, self);
            }
        });
    };
    // Constructor.
    {
        // Merge settings.
        $.extend(this.settings, configurationSettings);
        // Make the request.
        this.download();
    }
};

j'ai créé cette classe pour ajouter à ma bibliothèque JS. Il est réutilisable. Espérons que cela aide.

6
répondu George Siggouroglou 2017-05-23 12:34:18

vous pouvez utiliser ce plugin.

jQuery.download = function(url, data, method) {
    //url and data options required
    if (url && data) {
        //data can be string of parameters or array/object
        data = typeof data == 'string' ? data : jQuery.param(data);
        //split params into form inputs
        var inputs = '';
        jQuery.each(data.split('&'), function() {
            var pair = this.split('=');
            inputs += '<input type="hidden" name="' + pair[0] +
                '" value="' + pair[1] + '" />';
        });
        //send request
        jQuery('<form action="' + url +
                '" method="' + (method || 'post') + '">' + inputs + '</form>')
            .appendTo('body').submit().remove();
    };
};


$.download(
    '/export.php',
    'filename=mySpreadsheet&format=xls&content=' + spreadsheetData
);

ça a marché pour moi. Trouvé ce plugin ici

5
répondu IJas 2014-11-06 15:13:55

ce qui a fonctionné pour moi est le code suivant, car la fonction serveur récupère File(memoryStream.GetBuffer(), "application/pdf", "fileName.pdf");:

$http.get( fullUrl, { responseType: 'arraybuffer' })
            .success(function (response) {
                var blob = new Blob([response], { type: 'application/pdf' });

                if (window.navigator && window.navigator.msSaveOrOpenBlob) {
                    window.navigator.msSaveOrOpenBlob(blob); // for IE
                }
                else {
                    var fileURL = URL.createObjectURL(blob);
                    var newWin = window.open(fileURL);
                    newWin.focus();
                    newWin.reload();
                }
});
4
répondu ParPar 2016-07-17 15:24:24

créer une iframe cachée, puis dans votre code ajax ci-dessus:

url: document.getElementById('myiframeid').src = your_server_side_url ,

et supprimer le window.open(response);

2
répondu qalhat 2011-12-14 09:16:01

avez-vous de le faire avec Ajax? Ne serait-il pas possible de le charger dans un iframe?

1
répondu Emil Vikström 2010-01-04 13:44:29

cet extrait est pour les utilisateurs js angulaires qui feront face au même problème, notez que le fichier de réponse est téléchargé en utilisant un événement de clic programmé. Dans ce cas, les en-têtes ont été envoyés par le serveur contenant le nom du fichier et le contenu/type.

$http({
    method: 'POST', 
    url: 'DownloadAttachment_URL',
    data: { 'fileRef': 'filename.pdf' }, //I'm sending filename as a param
    headers: { 'Authorization': $localStorage.jwt === undefined ? jwt : $localStorage.jwt },
    responseType: 'arraybuffer',
}).success(function (data, status, headers, config) {
    headers = headers();
    var filename = headers['x-filename'];
    var contentType = headers['content-type'];
    var linkElement = document.createElement('a');
    try {
        var blob = new Blob([data], { type: contentType });
        var url = window.URL.createObjectURL(blob);

        linkElement.setAttribute('href', url);
        linkElement.setAttribute("download", filename);

        var clickEvent = new MouseEvent("click", {
            "view": window,
            "bubbles": true,
            "cancelable": false
        });
        linkElement.dispatchEvent(clickEvent);
    } catch (ex) {
        console.log(ex);
    }
}).error(function (data, status, headers, config) {
}).finally(function () {

});
1
répondu Gihan Sandaru 2018-04-09 14:26:42

concernant la réponse donnée par Mayur Padshala c'est la logique correcte pour télécharger un fichier pdf via ajax mais comme d'autres rapportent dans les commentaires Cette solution est en effet Téléchargements un fichier PDF vierge.

la raison en est expliquée dans la réponse acceptée de cette question : jQuery a quelques problèmes chargement de données binaires en utilisant des requêtes AJAX, car il ne met pas encore en œuvre certaines capacités HTML5 XHR v2, voir ceci amélioration de la demande et de cette discussion .

donc en utilisant HTMLHTTPRequest le code devrait ressembler à ceci:

var req = new XMLHttpRequest();
req.open("POST", "URL", true);
req.responseType = "blob";
req.onload = function (event) {
    var blob = req.response;
    var link=document.createElement('a');
    link.href=window.URL.createObjectURL(blob);
    link.download="name_for_the_file_to_save_with_extention";
    link.click();
}
1
répondu Vpant 2018-05-01 10:08:29

var xhr;
var beforeSend = function(){
    $('#pleasewaitDL').modal('show');
}
$(function () {
    $('#print_brochure_link').click(function(){
        beforeSend();
        xhr = new XMLHttpRequest();
        xhr.open("GET",$('#preparedPrintModalForm').attr('action'), true); 
        xhr.responseType = "blob";
        xhr.onload = function (e) {
            if (this.status === 200) {
                var file = window.URL.createObjectURL(this.response);
                var a = document.createElement("a");
                a.href = file;
                a.download = this.response.name || "Property Brochure";
                console.log(file);
                document.body.appendChild(a);
                a.click();
                
                window.onfocus = function () {                     
                  document.body.removeChild(a)
                }
                $('#pleasewaitDL').modal('hide');
            };
        };
        xhr.send($('#preparedPrintModalForm').serialize());
    });
    $('#pleasewaitDLCancel').click(function() {
        xhr.abort();
    });
});
0
répondu POGSNET 2017-04-07 03:50:41

si vous devez travailler avec file-stream (donc pas de PDF physiquement sauvegardé) comme nous le faisons et vous voulez télécharger le PDF sans page-reload, la fonction suivante fonctionne pour nous:

HTML

<div id="download-helper-hidden-container" style="display:none">
     <form id="download-helper-form" target="pdf-download-output" method="post">
            <input type="hidden" name="downloadHelperTransferData" id="downloadHelperTransferData" />
     </form>
     <iframe id="pdf-helper-output" name="pdf-download-output"></iframe>
</div>

Javascript

var form = document.getElementById('download-helper-form');
$("#downloadHelperTransferData").val(transferData);
form.action = "ServerSideFunctionWhichWritesPdfBytesToResponse";
form.submit();

en raison de la target= "pdf-download-output " , la réponse est écrite dans l'iframe et donc aucune page de rechargement n'est exécutée, mais le pdf-response-stream est sortie dans le navigateur à télécharger.

0
répondu George Maharis 2017-10-20 06:04:17