it-swarm.com.de

Herunterladen und öffnen PDF Datei mit Ajax

Ich habe eine Aktionsklasse, die ein PDF generiert. Die contentType wird entsprechend eingestellt.

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

Ich nenne dies action durch einen Ajax-Aufruf. Ich weiß nicht, wie ich diesen Stream an den Browser liefern kann. Ich habe ein paar Dinge ausprobiert, aber nichts hat funktioniert.

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

Das oben genannte gibt den Fehler an:

Ihr Browser hat eine Anfrage gesendet, die dieser Server nicht verstehen konnte.

79
Nayn

Sie brauchen dazu nicht unbedingt Ajax. Ein <a>-Link reicht aus, wenn Sie im serverseitigen Code content-disposition auf attachment setzen. Auf diese Weise bleibt die übergeordnete Seite nur geöffnet, wenn dies Ihr Hauptanliegen war (warum hätten Sie sich sonst unnötigerweise für Ajax entschieden?). Außerdem gibt es keine Möglichkeit, dies schön acynchronisch zu behandeln. PDF sind keine Zeichendaten. Es sind binäre Daten. Du kannst Sachen wie $(element).load() nicht machen. Sie möchten völlig neu Anfrage dazu verwenden. <a href="pdfservlet/filename.pdf">pdf</a> ist dafür bestens geeignet.

Um Sie mit dem serverseitigen Code besser zu unterstützen, müssen Sie mehr über die verwendete Sprache erfahren und einen Auszug der Code-Versuche posten.

33
BalusC

So habe ich das zum Laufen gebracht

$.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>

Aktualisierte Antwort mit download.js

$.ajax({
  url: '<URL_TO_FILE>',
  success: download.bind(true, "<FILENAME_TO_SAVE_WITH_EXTENSION>", "<FILE_MIME_TYPE>")
});

110
Mayur Padshala

Ich glaube nicht wirklich, dass eine der bisherigen Antworten das Problem des ursprünglichen Plakats herausgestellt hat. Sie alle gehen von einer GET-Anfrage aus, während das Poster Daten POST versuchte und als Antwort einen Download erhält.

Bei der Suche nach einer besseren Antwort haben wir dieses jQuery-Plugin für das Anfordern von Ajax-ähnlichen Dateidownloads gefunden.

Im "Herzen" wird ein "temporäres" HTML-Formular erstellt, das die angegebenen Daten als Eingabefelder enthält. Dieses Formular wird an das Dokument angehängt und an die gewünschte URL gesendet. Gleich danach wird das Formular wieder entfernt:

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

Update Mayurs Antwort sieht vielversprechend und sehr einfach aus, verglichen mit dem jQuery-Plug-In, auf das ich mich bezogen habe.

30
chiccodoro

So löse ich dieses Problem.
Die Antwort von Jonathan Amend am dieser Beitrag hat mir sehr geholfen.
Das folgende Beispiel ist vereinfacht.

Für weitere Informationen kann der obige Quellcode eine Datei mithilfe einer JQuery Ajax-Anforderung (GET, POST, PUT usw.) herunterladen. Es ist auch hilfreich, Parameter als JSON und den Inhaltstyp in application/json (meine Standardeinstellung) zu ändern hochzuladen.

Die html Quelle:

<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>  

Ein einfaches Formular mit zwei Eingabetexten, einem Auswahl- und einem Schaltflächenelement.

Die Javascript Seite Quelle:

<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>  

Ein einfaches Ereignis auf Knopfdruck. Es wird ein AjaxDownloadFile-Objekt erstellt. Die AjaxDownloadFile-Klassenquelle befindet sich unten.

Die AjaxDownloadFile Klasse Quelle:

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]*=(([""]).*?\2|[^;\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();
    }
};

Ich habe diese Klasse erstellt, um sie meiner JS-Bibliothek hinzuzufügen. Es ist wiederverwendbar. Ich hoffe, das hilft.

9

Was für mich funktioniert hat, ist der folgende Code, da die Serverfunktion File(memoryStream.GetBuffer(), "application/pdf", "fileName.pdf");: abruft.

$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();
                }
});
5
ParPar

Sie können dieses Plugin verwenden, das ein Formular erstellt, sendet und dann von der Seite entfernt.

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

Das hat bei mir funktioniert. Fand dieses Plugin hier

5
Ijas Ameenudeen

erstelle einen versteckten iframe, dann oben in deinem ajax-code:

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

und entfernen Sie die window.open(response);

2
qalhat

Müssen Sie es mit Ajax machen? Könnte es nicht möglich sein, es in einen iframe zu laden?

1
Emil Vikström

Um das leere Problem PDF in der Post-Anfrage zu beheben, um Stream-Daten wie PDF abzurufen, müssen Sie den Antworttyp als 'arraybuffer' oder 'blob' in der Anfrage hinzufügen

$.ajax({
  url: '<URL>',
  type: "POST",
  dataType: 'arraybuffer',
  success: function(data) {
    let blob = new Blob([data], {type: 'arraybuffer'});
    let link = document.createElement('a');
    let objectURL = window.URL.createObjectURL(blob);
    link.href = objectURL;
    link.target = '_self';
    link.download = "fileName.pdf";
    (document.body || document.documentElement).appendChild(link);
    link.click();
    setTimeout(()=>{
        window.URL.revokeObjectURL(objectURL);
        link.remove();
    }, 100);
  }
});
1
Ninja

Dieses Snippet wendet sich an Benutzer mit Winkeln js, die das gleiche Problem haben. Beachten Sie, dass die Antwortdatei mithilfe eines programmierten Klickereignisses heruntergeladen wird .. In diesem Fall wurden die Header vom Server gesendet, der Dateiname und Inhalt/Typ enthält.

$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
Gihan Sandaru

Bezüglich der Antwort von Mayur Padshala Dies ist die richtige Logik, um eine PDF-Datei über Ajax herunterzuladen, aber wie andere in den Kommentaren berichten, ist diese Lösung tatsächlich ein leeres PDF.

Der Grund dafür wird in der akzeptierten Antwort dieser question erklärt: jQuery hat einige Probleme beim Laden von Binärdaten mit AJAX - Anforderungen, da einige HTML5 XHR v2-Funktionen noch nicht implementiert sind. Siehe diese Erweiterung . Anfrage und diese Diskussion .

Bei Verwendung von HTMLHTTPRequest sollte der Code folgendermaßen aussehen:

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
Vpant

Der folgende Code hat für mich funktioniert

//Parameter to be passed
var data = 'reportid=R3823&isSQL=1&filter=[]';
var xhr = new XMLHttpRequest();
xhr.open("POST", "Reporting.jsp"); //url.It can pdf file path
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.responseType = "blob";
xhr.onload = function () {
    if (this.status === 200) {
        var blob = new Blob([xhr.response]);
        const url = window.URL.createObjectURL(blob);
        var a = document.createElement('a');
        a.href = url;
        a.download = 'myFile.pdf';
        a.click();
        setTimeout(function () {
            // For Firefox it is necessary to delay revoking the ObjectURL
            window.URL.revokeObjectURL(data)
                , 100
        })
    }
};
xhr.send(data);
1
MemZ

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
POGSNET

Wenn Sie mit File-Stream (also keine physisch gespeicherte PDF-Datei) wie wir arbeiten müssen und Sie die PDF ohne Page-Reload herunterladen möchten, funktioniert die folgende Funktion für uns:

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

Aufgrund der target = "pdf-download-output" wird die Antwort in den iframe geschrieben und daher kein Seiten-Reload ausgeführt, sondern der pdf-response-stream wird im Browser als Download ausgegeben.

0
George Maharis

Ich hoffe, das erspart Ihnen ein paar Stunden und erspart Ihnen Kopfschmerzen ... Es dauerte eine Weile, bis ich das herausgefunden habe, aber die regelmäßige $ .ajax () -Anforderung hat meine PDF -Datei ruiniert, während ich es durchgefordert hatte Adressleiste funktionierte einwandfrei . Lösung war dies:

Fügen Sie download.js ein: http://danml.com/download.html

Verwenden Sie dann XMLHttpRequest anstelle der $ .ajax () - Anforderung.

    var ajax = new XMLHttpRequest(); 

    ajax.open("GET", '/Admin/GetPdf' + id, true); 
    ajax.onreadystatechange = function(data) { 
        if (this.readyState == 4)
        {
            if (this.status == 200)
            {
                download(this.response, "report.pdf", "application/pdf");

            }
            else if (this.responseText != "")
            {
                alert(this.responseText);
            }
        }
        else if (this.readyState == 2)
        {
            if (this.status == 200)
            {
                this.responseType = "blob";
            }
            else
            {
                this.responseType = "text";
            }
        }
    };

    ajax.send(null);
0