JavaScript / jQuery zum Herunterladen von Dateien per POST mit JSON-Daten

250

Ich habe eine jquery-basierte einseitige Webanwendung. Es kommuniziert mit einem RESTful-Webdienst über AJAX-Aufrufe.

Ich versuche Folgendes zu erreichen:

  1. Senden Sie einen POST, der JSON-Daten enthält, an eine REST-URL.
  2. Wenn die Anforderung eine JSON-Antwort angibt, wird JSON zurückgegeben.
  3. Wenn die Anforderung eine PDF / XLS / etc-Antwort angibt, wird eine herunterladbare Binärdatei zurückgegeben.

Ich habe 1 & 2 jetzt arbeiten, und die Client-Abfrage-App zeigt die zurückgegebenen Daten auf der Webseite an, indem sie DOM-Elemente basierend auf den JSON-Daten erstellt. Ich habe auch # 3 aus der Sicht des Webdienstes, was bedeutet, dass eine Binärdatei erstellt und zurückgegeben wird, wenn die richtigen JSON-Parameter angegeben werden. Ich bin mir jedoch nicht sicher, wie ich am besten mit # 3 im Client-Javascript-Code umgehen soll.

Ist es möglich, eine herunterladbare Datei von einem Ajax-Aufruf wie diesem zurückzubekommen? Wie kann ich den Browser dazu bringen, die Datei herunterzuladen und zu speichern?

$.ajax({
    type: "POST",
    url: "/services/test",
    contentType: "application/json",
    data: JSON.stringify({category: 42, sort: 3, type: "pdf"}),
    dataType: "json",
    success: function(json, status){
        if (status != "success") {
            log("Error loading data");
            return;
        }
        log("Data loaded!");
    },
    error: function(result, status, err) {
        log("Error loading data");
        return;
    }
});

Der Server antwortet mit folgenden Headern:

Content-Disposition:attachment; filename=export-1282022272283.pdf
Content-Length:5120
Content-Type:application/pdf
Server:Jetty(6.1.11)

Eine andere Idee besteht darin, die PDF-Datei zu generieren, auf dem Server zu speichern und JSON zurückzugeben, das eine URL zur Datei enthält. Rufen Sie dann den Ajax Success Handler erneut auf, um Folgendes zu tun:

success: function(json,status) {
    window.location.href = json.url;
}

Dies bedeutet jedoch, dass ich mehr als einen Anruf beim Server tätigen muss und mein Server herunterladbare Dateien erstellen, irgendwo speichern und dann diesen Speicherbereich regelmäßig bereinigen muss.

Es muss einen einfacheren Weg geben, dies zu erreichen. Ideen?


BEARBEITEN: Nachdem ich die Dokumente auf $ .ajax überprüft habe, sehe ich, dass der Antwortdatentyp nur einer von sein xml, html, script, json, jsonp, textkann. Ich vermute, dass es keine Möglichkeit gibt, eine Datei mithilfe einer Ajax-Anforderung direkt herunterzuladen, es sei denn, ich binde die Binärdatei in using ein Daten-URI-Schema, wie in der @ VinayC-Antwort vorgeschlagen (was ich nicht tun möchte).

Ich denke also, meine Optionen sind:

  1. Verwenden Sie nicht Ajax und senden Sie stattdessen einen Formularbeitrag und binden Sie meine JSON-Daten in die Formularwerte ein. Müsste wahrscheinlich mit versteckten Iframes und so weiter herumspielen.

  2. Verwenden Sie nicht Ajax und konvertieren Sie stattdessen meine JSON-Daten in eine Abfragezeichenfolge, um eine Standard-GET-Anforderung zu erstellen und window.location.href auf diese URL zu setzen. Möglicherweise muss event.preventDefault () in meinem Klick-Handler verwendet werden, um zu verhindern, dass sich der Browser von der Anwendungs-URL ändert.

  3. Verwenden Sie meine andere Idee oben, aber erweitert mit Vorschlägen aus der @ naikus-Antwort. Senden Sie eine AJAX-Anfrage mit einem Parameter, der den Webdienst darüber informiert, dass dies über einen Ajax-Aufruf aufgerufen wird. Wenn der Webdienst von einem Ajax-Aufruf aufgerufen wird, geben Sie JSON einfach mit einer URL an die generierte Ressource zurück. Wenn die Ressource direkt aufgerufen wird, geben Sie die eigentliche Binärdatei zurück.

Je mehr ich darüber nachdenke, desto mehr gefällt mir die letzte Option. Auf diese Weise kann ich Informationen über die Anforderung (Zeit zum Generieren, Dateigröße, Fehlermeldungen usw.) zurückerhalten und auf diese Informationen reagieren, bevor ich mit dem Download beginne. Der Nachteil ist die zusätzliche Dateiverwaltung auf dem Server.

Gibt es noch andere Möglichkeiten, dies zu erreichen? Gibt es Vor- und Nachteile dieser Methoden, die mir bekannt sein sollten?

Tauren
quelle
Mögliches Duplikat des Handle-Dateidownloads von Ajax Post
IsmailS
6
Dieser war "ein bisschen" früher, also wie ist es ein Duplikat
GiM
1
url = 'http://localhost/file.php?file='+ $('input').val(); window.open(url); Der einfache Weg, um die gleichen Ergebnisse zu erzielen. Setzen Sie den Header in PHP-Datei. Keine Notwendigkeit,
Ajax

Antworten:

171

Die Lösung von letronje funktioniert nur für sehr einfache Seiten. document.body.innerHTML +=Nimmt den HTML-Text des Körpers, hängt den Iframe-HTML-Code an und setzt das innerHTML der Seite auf diese Zeichenfolge. Dadurch werden unter anderem alle Ereignisbindungen auf Ihrer Seite gelöscht. Erstellen Sie ein Element und verwenden Sie es appendChildstattdessen.

$.post('/create_binary_file.php', postData, function(retData) {
  var iframe = document.createElement("iframe");
  iframe.setAttribute("src", retData.url);
  iframe.setAttribute("style", "display: none");
  document.body.appendChild(iframe);
}); 

Oder mit jQuery

$.post('/create_binary_file.php', postData, function(retData) {
  $("body").append("<iframe src='" + retData.url+ "' style='display: none;' ></iframe>");
}); 

Was dies tatsächlich bewirkt: Führen Sie einen Beitrag in /create_binary_file.php mit den Daten in der Variablen postData aus. Wenn dieser Beitrag erfolgreich abgeschlossen wurde, fügen Sie dem Hauptteil der Seite einen neuen Iframe hinzu. Es wird davon ausgegangen, dass die Antwort von /create_binary_file.php den Wert 'url' enthält. Dies ist die URL, von der die generierte PDF / XLS / etc-Datei heruntergeladen werden kann. Das Hinzufügen eines Iframes zu der Seite, die auf diese URL verweist, führt dazu, dass der Browser den Benutzer zum Herunterladen der Datei auffordert, vorausgesetzt, der Webserver verfügt über die entsprechende MIME-Typkonfiguration.

SamStephens
quelle
1
Ich bin damit einverstanden, dies ist besser als die Verwendung +=und ich werde meine Anwendung entsprechend aktualisieren. Vielen Dank!
Tauren
3
Ich mag dieses Konzept, aber Chrome hat diese Meldung in der Konsole : Resource interpreted as Document but transferred with MIME type application/pdf. Dann warnt es mich auch, dass die Datei gefährlich sein kann. Wenn ich die retData.url direkt besuche, keine Warnungen oder Probleme.
Michael Irey
Wenn Sie sich im Internet umsehen, können Probleme mit PDFs in iFrames auftreten, wenn Ihr Server den Inhaltstyp und die Inhaltsdisposition nicht richtig einstellt. Ich habe diese Lösung nicht selbst verwendet, sondern nur eine frühere Lösung geklärt. Ich fürchte, ich habe keine anderen Ratschläge.
SamStephens
1
@Tauren: Wenn Sie damit einverstanden sind, dass dies eine bessere Antwort ist, können Sie die akzeptierte Antwort jederzeit ändern - oder sogar das Akzeptanzzeichen vollständig entfernen. Kreuzen Sie einfach die neue Antwort an und das Akzeptanzzeichen wird übertragen. (Alte Frage, aber sie wurde kürzlich in Flaggen erwähnt.)
BoltClock
5
Was soll die retData.url sein?
Mark Thien
48

Ich habe mit einer anderen Option herumgespielt, die Blobs verwendet. Ich habe es geschafft, Textdokumente herunterzuladen, und ich habe PDFs heruntergeladen (sie sind jedoch beschädigt).

Mit der Blob-API können Sie Folgendes tun:

$.post(/*...*/,function (result)
{
    var blob=new Blob([result]);
    var link=document.createElement('a');
    link.href=window.URL.createObjectURL(blob);
    link.download="myFileName.txt";
    link.click();

});

Dies ist IE 10+, Chrome 8+, FF 4+. Siehe https://developer.mozilla.org/en-US/docs/Web/API/URL.createObjectURL

Die Datei wird nur in Chrome, Firefox und Opera heruntergeladen. Hierbei wird ein Download-Attribut für das Ankertag verwendet, um den Browser zum Herunterladen zu zwingen.

JoshBerke
quelle
1
Keine Unterstützung für Download-Attribute in IE und Safari :( ( caniuse.com/#feat=download ). Sie können ein neues Fenster öffnen und dort Inhalte ablegen , sind sich jedoch nicht sicher, ob es sich um ein PDF oder Excel handelt ...
Marçal Juan
1
Sie sollten nach dem Aufruf Browser-Speicher clickwindow.URL.revokeObjectURL(link.href);
Edward Brey
@ JoshBerke Das ist alt, aber es funktioniert auf meiner Seite. Wie kann ich mein Verzeichnis sofort öffnen, um es zu speichern, anstatt es in meinem Browser zu speichern? Gibt es auch eine Möglichkeit, den Namen der eingehenden Datei zu bestimmen?
Jo Ko
2
Es wird Binärdateien beschädigen, weil sie mithilfe der Codierung in Zeichenfolgen konvertiert werden und das Ergebnis nicht sehr nahe an der ursprünglichen Binärdatei liegt ...
Gobol
2
Kann
Mateo Tibaquira
18

Ich kenne diese Art von alt, aber ich denke, ich habe eine elegantere Lösung gefunden. Ich hatte genau das gleiche Problem. Das Problem, das ich mit den vorgeschlagenen Lösungen hatte, war, dass alle die Datei auf dem Server speichern mussten, aber ich wollte die Dateien nicht auf dem Server speichern, da dies andere Probleme mit sich brachte (Sicherheit: Auf die Datei konnte dann zugegriffen werden nicht authentifizierte Benutzer, Bereinigung: Wie und wann werden die Dateien entfernt? Und wie Sie waren meine Daten komplexe, verschachtelte JSON-Objekte, die sich nur schwer in ein Formular einfügen lassen.

Ich habe zwei Serverfunktionen erstellt. Der erste validierte die Daten. Wenn ein Fehler aufgetreten ist, wird er zurückgegeben. Wenn es kein Fehler war, habe ich alle Parameter zurückgegeben, die als base64-Zeichenfolge serialisiert / codiert wurden. Dann habe ich auf dem Client ein Formular, das nur eine versteckte Eingabe hat und an eine zweite Serverfunktion sendet. Ich setze die versteckte Eingabe auf die base64-Zeichenfolge und sende das Format. Die zweite Serverfunktion dekodiert / deserialisiert die Parameter und generiert die Datei. Das Formular kann an ein neues Fenster oder einen Iframe auf der Seite gesendet werden, und die Datei wird geöffnet.

Es ist ein bisschen mehr Arbeit und vielleicht ein bisschen mehr Verarbeitung erforderlich, aber insgesamt habe ich mich mit dieser Lösung viel besser gefühlt.

Code ist in C # / MVC

    public JsonResult Validate(int reportId, string format, ReportParamModel[] parameters)
    {
        // TODO: do validation

        if (valid)
        {
            GenerateParams generateParams = new GenerateParams(reportId, format, parameters);

            string data = new EntityBase64Converter<GenerateParams>().ToBase64(generateParams);

            return Json(new { State = "Success", Data = data });
        }

        return Json(new { State = "Error", Data = "Error message" });
    }

    public ActionResult Generate(string data)
    {
        GenerateParams generateParams = new EntityBase64Converter<GenerateParams>().ToEntity(data);

        // TODO: Generate file

        return File(bytes, mimeType);
    }

auf dem Client

    function generate(reportId, format, parameters)
    {
        var data = {
            reportId: reportId,
            format: format,
            params: params
        };

        $.ajax(
        {
            url: "/Validate",
            type: 'POST',
            data: JSON.stringify(data),
            dataType: 'json',
            contentType: 'application/json; charset=utf-8',
            success: generateComplete
        });
    }

    function generateComplete(result)
    {
        if (result.State == "Success")
        {
            // this could/should already be set in the HTML
            formGenerate.action = "/Generate";
            formGenerate.target = iframeFile;

            hidData = result.Data;
            formGenerate.submit();
        }
        else
            // TODO: display error messages
    }
amersk
quelle
1
Ich habe mir diese Lösung nicht genau angesehen, aber es ist erwähnenswert, dass nichts an der Lösung mit create_binary_file.php das Speichern von Dateien auf der Festplatte erfordert. Es wäre durchaus möglich, dass create_binary_file.php Binärdateien im Speicher generiert.
SamStephens
11

Es gibt eine einfachere Möglichkeit, ein Formular zu erstellen und zu veröffentlichen. Dies birgt das Risiko, dass die Seite zurückgesetzt wird, wenn ein Browser den Typ "Return Mime" öffnen würde, aber für CSV und dergleichen ist er perfekt

Beispiel erfordert Unterstrich und Abfrage

var postData = {
    filename:filename,
    filecontent:filecontent
};
var fakeFormHtmlFragment = "<form style='display: none;' method='POST' action='"+SAVEAS_PHP_MODE_URL+"'>";
_.each(postData, function(postValue, postKey){
    var escapedKey = postKey.replace("\\", "\\\\").replace("'", "\'");
    var escapedValue = postValue.replace("\\", "\\\\").replace("'", "\'");
    fakeFormHtmlFragment += "<input type='hidden' name='"+escapedKey+"' value='"+escapedValue+"'>";
});
fakeFormHtmlFragment += "</form>";
$fakeFormDom = $(fakeFormHtmlFragment);
$("body").append($fakeFormDom);
$fakeFormDom.submit();

Stellen Sie für Dinge wie HTML, Text und dergleichen sicher, dass der Mimetyp etwas wie Anwendung / Oktett-Stream ist

PHP-Code

<?php
/**
 * get HTTP POST variable which is a string ?foo=bar
 * @param string $param
 * @param bool $required
 * @return string
 */
function getHTTPPostString ($param, $required = false) {
    if(!isset($_POST[$param])) {
        if($required) {
            echo "required POST param '$param' missing";
            exit 1;
        } else {
            return "";
        }
    }
    return trim($_POST[$param]);
}

$filename = getHTTPPostString("filename", true);
$filecontent = getHTTPPostString("filecontent", true);

header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"$filename\"");
echo $filecontent;
aqm
quelle
8

Kurz gesagt, es gibt keinen einfacheren Weg. Sie müssen eine weitere Serveranforderung stellen, um die PDF-Datei anzuzeigen. Es gibt zwar nur wenige Alternativen, diese sind jedoch nicht perfekt und funktionieren nicht in allen Browsern:

  1. Sehen Sie sich das Daten-URI-Schema an . Wenn Binärdaten klein sind, können Sie möglicherweise Javascript verwenden, um Fenster zu öffnen, die Daten in URI übergeben.
  2. Die einzige Windows / IE-Lösung wäre, über .NET-Steuerelemente oder FileSystemObject zu verfügen, um die Daten im lokalen Dateisystem zu speichern und von dort aus zu öffnen.
VinayC
quelle
Vielen Dank, mir war das Daten-URI-Schema nicht bekannt. Es sieht so aus, als wäre dies der einzige Weg, dies in einer einzigen Anfrage zu tun. Aber es ist nicht wirklich die Richtung, in die ich gehen möchte.
Tauren
Aufgrund der Clientanforderungen habe ich dieses Problem mithilfe der Server-Header in der Antwort ( Content-Disposition: attachment;filename="file.txt") gelöst , aber ich möchte diesen Ansatz beim nächsten Mal unbedingt ausprobieren. Ich hatte zuvor URIDaten für Miniaturansichten verwendet, aber es kam mir nie in den Sinn, sie für Downloads zu verwenden - danke, dass Sie dieses Nugget geteilt haben.
Brichins
8

Es ist schon eine Weile her, dass diese Frage gestellt wurde, aber ich hatte die gleiche Herausforderung und möchte meine Lösung teilen. Es werden Elemente aus den anderen Antworten verwendet, aber ich konnte es nicht vollständig finden. Es wird weder ein Formular noch ein Iframe verwendet, es ist jedoch ein Post / Get-Anforderungspaar erforderlich. Anstatt die Datei zwischen den Anforderungen zu speichern, werden die Post-Daten gespeichert. Es scheint sowohl einfach als auch effektiv zu sein.

Klient

var apples = new Array(); 
// construct data - replace with your own
$.ajax({
   type: "POST",
   url: '/Home/Download',
   data: JSON.stringify(apples),
   contentType: "application/json",
   dataType: "text",

   success: function (data) {
      var url = '/Home/Download?id=' + data;
      window.location = url;
   });
});

Server

[HttpPost]
// called first
public ActionResult Download(Apple[] apples)
{
   string json = new JavaScriptSerializer().Serialize(apples);
   string id = Guid.NewGuid().ToString();
   string path = Server.MapPath(string.Format("~/temp/{0}.json", id));
   System.IO.File.WriteAllText(path, json);

   return Content(id);
}

// called next
public ActionResult Download(string id)
{
   string path = Server.MapPath(string.Format("~/temp/{0}.json", id));
   string json = System.IO.File.ReadAllText(path);
   System.IO.File.Delete(path);
   Apple[] apples = new JavaScriptSerializer().Deserialize<Apple[]>(json);

   // work with apples to build your file in memory
   byte[] file = createPdf(apples); 

   Response.AddHeader("Content-Disposition", "attachment; filename=juicy.pdf");
   return File(file, "application/pdf");
}
Frank Rem
quelle
1
Ich denke, diese Lösung gefällt mir am besten. In meinem Fall, obwohl ich die Datei generiere, denke ich, dass ich versuchen werde, die Datei im Speicher zu belassen, bis auf sie zugegriffen wird, und dann den Speicher nach dem Herunterladen freigeben werde, damit ich nie auf die Festplatte schreiben muss.
BVernon
5
$scope.downloadSearchAsCSV = function(httpOptions) {
  var httpOptions = _.extend({
    method: 'POST',
    url:    '',
    data:   null
  }, httpOptions);
  $http(httpOptions).then(function(response) {
    if( response.status >= 400 ) {
      alert(response.status + " - Server Error \nUnable to download CSV from POST\n" + JSON.stringify(httpOptions.data));
    } else {
      $scope.downloadResponseAsCSVFile(response)
    }
  })
};
/**
 * @source: https://github.com/asafdav/ng-csv/blob/master/src/ng-csv/directives/ng-csv.js
 * @param response
 */
$scope.downloadResponseAsCSVFile = function(response) {
  var charset = "utf-8";
  var filename = "search_results.csv";
  var blob = new Blob([response.data], {
    type: "text/csv;charset="+ charset + ";"
  });

  if (window.navigator.msSaveOrOpenBlob) {
    navigator.msSaveBlob(blob, filename); // @untested
  } else {
    var downloadContainer = angular.element('<div data-tap-disabled="true"><a></a></div>');
    var downloadLink      = angular.element(downloadContainer.children()[0]);
    downloadLink.attr('href', window.URL.createObjectURL(blob));
    downloadLink.attr('download', "search_results.csv");
    downloadLink.attr('target', '_blank');

    $document.find('body').append(downloadContainer);

    $timeout(function() {
      downloadLink[0].click();
      downloadLink.remove();
    }, null);
  }

  //// Gets blocked by Chrome popup-blocker
  //var csv_window = window.open("","","");
  //csv_window.document.write('<meta name="content-type" content="text/csv">');
  //csv_window.document.write('<meta name="content-disposition" content="attachment;  filename=data.csv">  ');
  //csv_window.document.write(response.data);
};
James McGuigan
quelle
3

Nicht nur eine Antwort auf den ursprünglichen Beitrag, sondern eine schnelle und schmutzige Lösung, um ein JSON-Objekt auf dem Server zu veröffentlichen und dynamisch einen Download zu generieren.

Clientseitige jQuery:

var download = function(resource, payload) {
     $("#downloadFormPoster").remove();
     $("<div id='downloadFormPoster' style='display: none;'><iframe name='downloadFormPosterIframe'></iframe></div>").appendTo('body');
     $("<form action='" + resource + "' target='downloadFormPosterIframe' method='post'>" +
      "<input type='hidden' name='jsonstring' value='" + JSON.stringify(payload) + "'/>" +
      "</form>")
      .appendTo("#downloadFormPoster")
      .submit();
}

..und dann die JSON-Zeichenfolge auf der Serverseite dekodieren und Header zum Herunterladen festlegen (PHP-Beispiel):

$request = json_decode($_POST['jsonstring']), true);
header('Content-Type: application/csv');
header('Content-Disposition: attachment; filename=export.csv');
header('Pragma: no-cache');
ralftar
quelle
Ich mag diese Lösung. In der Frage des OP klingt es so, als ob der Anforderer weiß, ob er einen Dateidownload oder JSON-Daten erwarten soll, sodass er sich auf Client-Seite entscheiden und unter einer anderen URL posten kann, anstatt sich auf Server-Seite zu entscheiden.
Sam
2

Ich denke, der beste Ansatz ist die Verwendung einer Kombination. Ihr zweiter Ansatz scheint eine elegante Lösung zu sein, wenn Browser beteiligt sind.

Also je nachdem, wie der Anruf getätigt wird. (ob es sich um einen Browser oder einen Webdienstaufruf handelt) Sie können eine Kombination aus beiden verwenden, indem Sie eine URL an den Browser senden und Rohdaten an einen anderen Webdienstclient senden.

Naikus
quelle
Mein zweiter Ansatz sieht jetzt auch für mich ansprechender aus. Vielen Dank für die Bestätigung, dass es sich um eine lohnende Lösung handelt. Schlagen Sie vor, dass ich im json-Objekt einen zusätzlichen Wert übergebe, der angibt, dass diese Anforderung von einem Browser als Ajax-Aufruf anstelle eines Webdienstaufrufs erfolgt? Es gibt verschiedene Möglichkeiten, dies zu erreichen, aber welche Technik würden Sie verwenden?
Tauren
Kann das nicht durch den User-Agent-HTTP-Header bestimmt werden? Oder irgendein anderer http-Header?
Naikus
1

Ich bin jetzt seit zwei Tagen wach und versuche herauszufinden, wie ich eine Datei mit jquery mit Ajax-Aufruf herunterladen kann. All die Unterstützung, die ich bekam, konnte meiner Situation nicht helfen, bis ich es versuchte.

Client-Seite

function exportStaffCSV(t) {
   
    var postData = { checkOne: t };
    $.ajax({
        type: "POST",
        url: "/Admin/Staff/exportStaffAsCSV",
        data: postData,
        success: function (data) {
            SuccessMessage("file download will start in few second..");
            var url = '/Admin/Staff/DownloadCSV?data=' + data;
            window.location = url;
        },
       
        traditional: true,
        error: function (xhr, status, p3, p4) {
            var err = "Error " + " " + status + " " + p3 + " " + p4;
            if (xhr.responseText && xhr.responseText[0] == "{")
                err = JSON.parse(xhr.responseText).Message;
            ErrorMessage(err);
        }
    });

}

Serverseite

 [HttpPost]
    public string exportStaffAsCSV(IEnumerable<string> checkOne)
    {
        StringWriter sw = new StringWriter();
        try
        {
            var data = _db.staffInfoes.Where(t => checkOne.Contains(t.staffID)).ToList();
            sw.WriteLine("\"First Name\",\"Last Name\",\"Other Name\",\"Phone Number\",\"Email Address\",\"Contact Address\",\"Date of Joining\"");
            foreach (var item in data)
            {
                sw.WriteLine(string.Format("\"{0}\",\"{1}\",\"{2}\",\"{3}\",\"{4}\",\"{5}\",\"{6}\"",
                    item.firstName,
                    item.lastName,
                    item.otherName,
                    item.phone,
                    item.email,
                    item.contact_Address,
                    item.doj
                    ));
            }
        }
        catch (Exception e)
        {

        }
        return sw.ToString();

    }

    //On ajax success request, it will be redirected to this method as a Get verb request with the returned date(string)
    public FileContentResult DownloadCSV(string data)
    {
        return File(new System.Text.UTF8Encoding().GetBytes(data), System.Net.Mime.MediaTypeNames.Application.Octet, filename);
        //this method will now return the file for download or open.
    }

Viel Glück.

Otis-iDev
quelle
2
Dies funktioniert für kleine Dateien. Wenn Sie jedoch eine große Datei haben, werden Sie auf das Problem stoßen, dass die URL zu lang ist. Versuchen Sie es mit 1.000 Datensätzen, es wird kaputt gehen und nur einen Teil der Daten exportieren.
Michael Merrell
1

Ich habe es vor langer Zeit irgendwo gefunden und es funktioniert perfekt!

let payload = {
  key: "val",
  key2: "val2"
};

let url = "path/to/api.php";
let form = $('<form>', {'method': 'POST', 'action': url}).hide();
$.each(payload, (k, v) => form.append($('<input>', {'type': 'hidden', 'name': k, 'value': v})) );
$('body').append(form);
form.submit();
form.remove();
Den Nikitin
quelle
0

Ein anderer Ansatz, anstatt die Datei auf dem Server zu speichern und abzurufen, besteht darin, .NET 4.0+ ObjectCache mit einem kurzen Ablauf bis zur zweiten Aktion zu verwenden (zu diesem Zeitpunkt kann sie endgültig gesichert werden). Der Grund, warum ich JQuery Ajax verwenden möchte, um den Aufruf auszuführen, ist, dass er asynchron ist. Das Erstellen meiner dynamischen PDF-Datei nimmt einige Zeit in Anspruch, und während dieser Zeit wird ein belebter Drehfelddialog angezeigt (es können auch andere Arbeiten ausgeführt werden). Der Ansatz, die im "Erfolg:" zurückgegebenen Daten zum Erstellen eines Blobs zu verwenden, funktioniert nicht zuverlässig. Dies hängt vom Inhalt der PDF-Datei ab. Es kann leicht durch Daten in der Antwort beschädigt werden, wenn es nicht vollständig textuell ist, was alles ist, was Ajax verarbeiten kann.

Wray Smallwood
quelle
0

Lösung

Content-Disposition-Anhang scheint für mich zu funktionieren:

self.set_header("Content-Type", "application/json")
self.set_header("Content-Disposition", 'attachment; filename=learned_data.json')

Problemumgehung

Anwendung / Oktett-Stream

Bei einem JSON passierte mir etwas Ähnliches. Auf der Serverseite setzte ich den Header auf self.set_header ("Content-Type", " application / json "), als ich ihn jedoch änderte in:

self.set_header("Content-Type", "application/octet-stream")

Es wurde automatisch heruntergeladen.

Beachten Sie auch, dass die Datei weiterhin das Suffix .json enthält, das Sie im Dateinamen-Header benötigen:

self.set_header("Content-Disposition", 'filename=learned_data.json')
Mr-Programme
quelle
-1

Mit HTML5 können Sie einfach einen Anker erstellen und darauf klicken. Es ist nicht erforderlich, es als untergeordnetes Dokument zum Dokument hinzuzufügen.

const a = document.createElement('a');
a.download = '';
a.href = urlForPdfFile;
a.click();

Alles erledigt.

Wenn Sie einen speziellen Namen für den Download haben möchten, übergeben Sie ihn einfach im downloadAttribut:

const a = document.createElement('a');
a.download = 'my-special-name.pdf';
a.href = urlForPdfFile;
a.click();
umgeschrieben
quelle
4
Die Frage ist über die POST-Methode
Dovid