501 Stimmen

Herunterladen einer Datei mit jQuery.Ajax

Ich habe eine Struts2-Aktion auf der Serverseite zum Herunterladen von Dateien.

<action name="download" class="com.xxx.DownAction">
    <result name="success" type="stream">
        <param name="contentType">text/plain</param>
        <param name="inputName">imageStream</param>
        <param name="contentDisposition">attachment;filename={fileName}</param>
        <param name="bufferSize">1024</param>
    </result>
</action>

Wenn ich jedoch die Aktion mit dem jQuery:

$.post(
  "/download.action",{
    para1:value1,
    para2:value2
    ....
  },function(data){
      console.info(data);
   }
);

in Firebug sehe ich, dass die Daten mit der Binärer Strom . Ich frage mich, wie man die Fenster zum Herunterladen von Dateien mit der der Benutzer die Datei lokal speichern kann?

4voto

Andrew Koster Punkte 1269

Utilisez window.open https://developer.mozilla.org/en-US/docs/Web/API/Window/open

Sie können zum Beispiel diese Codezeile in einen Click-Handler einfügen:

window.open('/file.txt', '_blank');

Es wird eine neue Registerkarte geöffnet (wegen des Fensternamens "_blank"), und in dieser Registerkarte wird die URL geöffnet.

Ihr serverseitiger Code sollte auch so etwas wie dies enthalten:

res.set('Content-Disposition', 'attachment; filename=file.txt');

Auf diese Weise sollte der Browser den Benutzer auffordern, die Datei auf der Festplatte zu speichern, anstatt ihm die Datei nur anzuzeigen. Außerdem wird die gerade geöffnete Registerkarte automatisch geschlossen.

4voto

dario nascimento Punkte 536

Ergänzung der obigen Antwort zum Herunterladen einer Datei um einige weitere Punkte

Nachfolgend finden Sie einen Java Spring Code, der ein Byte Array erzeugt

@RequestMapping(value = "/downloadReport", method = { RequestMethod.POST })
    public ResponseEntity<byte[]> downloadReport(
            @RequestBody final SomeObejct obj, HttpServletResponse response) throws Exception {

        OutputStream out = new ByteArrayOutputStream();
        // write something to output stream
        HttpHeaders respHeaders = new HttpHeaders();
        respHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        respHeaders.add("X-File-Name", name);
        ByteArrayOutputStream bos = (ByteArrayOutputStream) out;
        return new ResponseEntity<byte[]>(bos.toByteArray(), respHeaders, HttpStatus.CREATED);
    }

Jetzt in Javascript-Code mit FileSaver.js, kann eine Datei mit untenstehenden Code herunterladen

var json=angular.toJson("somejsobject");
var url=apiEndPoint+'some url';
var xhr = new XMLHttpRequest();
//headers('X-File-Name')
xhr.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 201) {
        var res = this.response;
        var fileName=this.getResponseHeader('X-File-Name');
        var data = new Blob([res]);
        saveAs(data, fileName); //this from FileSaver.js
    }
}    
xhr.open('POST', url);
xhr.setRequestHeader('Authorization','Bearer ' + token);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.responseType = 'arraybuffer';
xhr.send(json);

Die oben genannte Datei wird heruntergeladen

2voto

Yannick Richard Punkte 1209

Ok, so ist hier der Arbeitscode, wenn mit MVC und Sie erhalten Ihre Datei von einem Controller

Nehmen wir an, Sie haben Ihr Byte-Array deklariert und aufgefüllt. Das Einzige, was Sie tun müssen, ist, die File-Funktion zu verwenden (mit System.Web.Mvc)

byte[] bytes = .... insert your bytes in the array
return File(bytes, System.Net.Mime.MediaTypeNames.Application.Octet, "nameoffile.exe");

und fügen Sie dann in demselben Controller diese 2 Funktionen hinzu

protected override void OnResultExecuting(ResultExecutingContext context)
    {
        CheckAndHandleFileResult(context);

        base.OnResultExecuting(context);
    }

    private const string FILE_DOWNLOAD_COOKIE_NAME = "fileDownload";

    /// <summary>
    /// If the current response is a FileResult (an MVC base class for files) then write a
    /// cookie to inform jquery.fileDownload that a successful file download has occured
    /// </summary>
    /// <param name="context"></param>
    private void CheckAndHandleFileResult(ResultExecutingContext context)
    {
        if (context.Result is FileResult)
            //jquery.fileDownload uses this cookie to determine that a file download has completed successfully
            Response.SetCookie(new HttpCookie(FILE_DOWNLOAD_COOKIE_NAME, "true") { Path = "/" });
        else
            //ensure that the cookie is removed in case someone did a file download without using jquery.fileDownload
            if (Request.Cookies[FILE_DOWNLOAD_COOKIE_NAME] != null)
                Response.Cookies[FILE_DOWNLOAD_COOKIE_NAME].Expires = DateTime.Now.AddYears(-1);
    }

und dann können Sie Ihren Controller zum Herunterladen aufrufen und den Rückruf "Erfolg" oder "Misserfolg" erhalten

$.fileDownload(mvcUrl('name of the controller'), {
            httpMethod: 'POST',
            successCallback: function (url) {
            //insert success code

            },
            failCallback: function (html, url) {
            //insert fail code
            }
        });

1voto

Kit Ramos Punkte 1301

Ich habe eine Lösung gefunden, die zwar nicht wirklich Ajax verwendet, es aber erlaubt, einen Javascript-Aufruf zu verwenden, um den Download anzufordern und dann einen Rückruf zu erhalten, wenn der Download tatsächlich beginnt. Ich fand dies hilfreich, wenn der Link läuft ein Server-Side-Skript, das ein wenig dauert, um die Datei vor dem Senden zu komponieren. so können Sie sie alarmieren, dass es die Verarbeitung ist, und dann, wenn es schließlich die Datei zu senden, entfernen Sie diese Verarbeitung Benachrichtigung. das ist, warum ich wollte versuchen, die Datei über Ajax zu laden, um mit zu beginnen, so dass ich ein Ereignis passieren, wenn die Datei angefordert wird und eine andere, wenn es tatsächlich beginnt das Herunterladen haben könnte.

die js auf der Titelseite

function expdone()
{
    document.getElementById('exportdiv').style.display='none';
}
function expgo()
{
   document.getElementById('exportdiv').style.display='block';
   document.getElementById('exportif').src='test2.php?arguments=data';
}

der iframe

<div id="exportdiv" style="display:none;">
<img src="loader.gif"><br><h1>Generating Report</h1>
<iframe id="exportif" src="" style="width: 1px;height: 1px; border:0px;"></iframe>
</div>

dann die andere Datei:

<!DOCTYPE html>
<html>
<head>
<script>
function expdone()
{
    window.parent.expdone();
}
</script>
</head>
<body>
<iframe id="exportif" src="<?php echo "http://10.192.37.211/npdtracker/exportthismonth.php?arguments=".$_GET["arguments"]; ?>"></iframe>
<script>document.getElementById('exportif').onload= expdone;</script>
</body></html>

Ich denke, es gibt einen Weg, um Daten mit Js zu lesen, so dass dann kein PHP erforderlich wäre. aber ich weiß es nicht aus der Hand und der Server, den ich verwende, unterstützt PHP, so dass dies für mich funktioniert. dachte ich würde es teilen, falls es jemandem hilft.

1voto

Pierre Punkte 7297

Wenn der Server die Datei in der Antwort zurückschreibt (einschließlich Cookies, wenn Sie verwenden sie, um festzustellen, ob der Dateidownload begonnen hat), erstellen Sie einfach ein Formular mit den Werten und senden es ab:

function ajaxPostDownload(url, data) {
    var $form;
    if (($form = $('#download_form')).length === 0) {
        $form = $("<form id='download_form'" + " style='display: none; width: 1px; height: 1px; position: absolute; top: -10000px' method='POST' action='" + url + "'></form>");
        $form.appendTo("body");
    }
    //Clear the form fields
    $form.html("");
    //Create new form fields
    Object.keys(data).forEach(function (key) {
        $form.append("<input type='hidden' name='" + key + "' value='" + data[key] + "'>");
    });
    //Submit the form post
    $form.submit();
}

Verwendung:

ajaxPostDownload('/fileController/ExportFile', {
    DownloadToken: 'newDownloadToken',
    Name: $txtName.val(),
    Type: $txtType.val()
});

Controller-Methode:

[HttpPost]
public FileResult ExportFile(string DownloadToken, string Name, string Type)
{
    //Set DownloadToken Cookie.
    Response.SetCookie(new HttpCookie("downloadToken", DownloadToken)
    {
        Expires = DateTime.UtcNow.AddDays(1),
        Secure = false
    });

    using (var output = new MemoryStream())
    {
        //get File
        return File(output.ToArray(), "application/vnd.ms-excel", "NewFile.xls");
    }
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X