JavaScript / jQuery untuk mengunduh file melalui POST dengan data JSON

250

Saya memiliki webapp halaman tunggal berbasis jquery. Ini berkomunikasi dengan layanan web yang tenang melalui panggilan AJAX.

Saya mencoba mencapai yang berikut:

  1. Kirim POST yang berisi data JSON ke url REST.
  2. Jika permintaan menentukan respons JSON, maka JSON dikembalikan.
  3. Jika permintaan menentukan tanggapan PDF / XLS / etc, maka biner yang dapat diunduh dikembalikan.

Saya memiliki 1 & 2 yang berfungsi sekarang, dan aplikasi jquery klien menampilkan data yang dikembalikan di halaman web dengan membuat elemen DOM berdasarkan pada data JSON. Saya juga memiliki # 3 yang berfungsi dari sudut pandang layanan web, artinya akan membuat dan mengembalikan file biner jika diberi parameter JSON yang benar. Tapi saya tidak yakin cara terbaik untuk menangani # 3 dalam kode javascript klien.

Apakah mungkin untuk mendapatkan file yang dapat diunduh kembali dari panggilan ajax seperti ini? Bagaimana cara mendapatkan browser untuk mengunduh dan menyimpan file?

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

Server merespons dengan tajuk berikut:

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

Gagasan lain adalah membuat PDF dan menyimpannya di server dan mengembalikan JSON yang menyertakan URL ke file. Kemudian, panggil panggilan lain di penangan sukses ajax untuk melakukan sesuatu seperti berikut:

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

Tetapi melakukan itu berarti saya perlu melakukan lebih dari satu panggilan ke server, dan server saya perlu membuat file yang dapat diunduh, menyimpannya di suatu tempat, kemudian secara berkala membersihkan area penyimpanan itu.

Pasti ada cara yang lebih sederhana untuk mencapai ini. Ide ide?


EDIT: Setelah meninjau dokumen seharga $ .ajax, saya melihat bahwa tipe data respon hanya bisa salah satunya xml, html, script, json, jsonp, text, jadi saya kira tidak ada cara untuk langsung mengunduh file menggunakan permintaan ajax, kecuali saya menyematkan file biner dalam menggunakan Skema URI data seperti yang disarankan dalam jawaban @VinayC (yang bukan sesuatu yang ingin saya lakukan).

Jadi saya kira pilihan saya adalah:

  1. Tidak menggunakan ajax dan sebagai gantinya mengirimkan formulir posting dan embed data JSON saya ke dalam nilai formulir. Mungkin perlu dipusingkan dengan iframe tersembunyi dan semacamnya.

  2. Tidak menggunakan ajax dan sebaliknya mengubah data JSON saya menjadi string kueri untuk membangun permintaan GET standar dan mengatur window.location.href ke URL ini. Mungkin perlu menggunakan event.preventDefault () di penangan klik saya untuk menjaga browser agar tidak berubah dari URL aplikasi.

  3. Gunakan ide saya yang lain di atas, tetapi ditingkatkan dengan saran dari jawaban @aikus. Kirim permintaan AJAX dengan beberapa parameter yang memungkinkan layanan web tahu bahwa ini dipanggil melalui panggilan ajax. Jika layanan web dipanggil dari panggilan ajax, cukup kembalikan JSON dengan URL ke sumber yang dihasilkan. Jika sumber daya dipanggil secara langsung, maka kembalikan file biner yang sebenarnya.

Semakin saya memikirkannya, semakin saya suka pilihan terakhir. Dengan cara ini saya dapat memperoleh kembali informasi tentang permintaan (waktu untuk menghasilkan, ukuran file, pesan kesalahan, dll.) Dan saya dapat bertindak atas informasi itu sebelum memulai pengunduhan. Kelemahannya adalah manajemen file tambahan di server.

Adakah cara lain untuk mencapai ini? Adakah kelebihan / kekurangan untuk metode ini yang harus saya ketahui?

Tauren
sumber
kemungkinan duplikat unduhan file Handle dari pos ajax
IsmailS
6
yang ini "sedikit" sebelumnya, jadi bagaimana itu duplikat
GiM
1
url = 'http://localhost/file.php?file='+ $('input').val(); window.open(url); Cara mudah untuk mendapatkan hasil yang sama. Masukkan header dalam file php. Tidak perlu mengirim ajax atau mendapatkan permintaan
abhishek bagul

Jawaban:

171

solusi letronje hanya berfungsi untuk halaman yang sangat sederhana. document.body.innerHTML +=mengambil teks HTML dari badan, menambahkan iframe HTML, dan mengatur innerHTML halaman ke string itu. Ini akan menghapus semua peristiwa yang mengikat laman Anda, di antara hal-hal lain. Buat elemen dan gunakan appendChildsebagai gantinya.

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

Atau menggunakan jQuery

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

Apa ini sebenarnya tidak: melakukan posting ke /create_binary_file.php dengan data dalam variabel postData; jika posting itu selesai dengan sukses, tambahkan iframe baru ke badan halaman. Asumsinya adalah bahwa respons dari /create_binary_file.php akan menyertakan nilai 'url', yang merupakan URL tempat file PDF / XLS / etc yang dihasilkan dapat diunduh. Menambahkan iframe ke halaman yang mereferensikan URL yang akan menghasilkan browser mempromosikan pengguna untuk mengunduh file, dengan asumsi bahwa server web memiliki konfigurasi tipe mime yang sesuai.

SamStephens
sumber
1
Saya setuju, ini lebih baik daripada menggunakan +=dan saya akan memperbarui aplikasi saya sesuai. Terima kasih!
Tauren
3
Saya suka konsep ini, namun Chrome memiliki pesan ini di konsol: Resource interpreted as Document but transferred with MIME type application/pdf. Maka itu juga memperingatkan saya file tersebut mungkin berbahaya. Jika saya mengunjungi retData.url secara langsung, tidak ada peringatan atau masalah.
Michael Irey
Mencari di internet, sepertinya Anda dapat memiliki masalah dengan PDF di iFrames jika server Anda tidak mengatur Content-Type dan Content-Disposition dengan benar. Saya belum benar-benar menggunakan solusi ini sendiri, hanya mengklarifikasi solusi sebelumnya, jadi saya tidak punya saran lain.
SamStephens
1
@Tauren: Jika Anda setuju bahwa ini adalah jawaban yang lebih baik, perhatikan bahwa Anda dapat mengalihkan jawaban yang diterima kapan saja - atau bahkan menghapus tanda terima seluruhnya. Cukup centang jawaban baru dan tanda terima akan ditransfer. (Pertanyaan lama, tetapi dibesarkan dengan bendera baru-baru ini.)
BoltClock
5
apa retData.url seharusnya?
Mark Thien
48

Saya telah bermain-main dengan opsi lain yang menggunakan gumpalan. Saya sudah berhasil mendapatkannya untuk mengunduh dokumen teks, dan saya sudah mengunduh PDF (Namun mereka rusak).

Menggunakan gumpalan API Anda akan dapat melakukan hal berikut:

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

});

Ini adalah IE 10+, Chrome 8+, FF 4+. Lihat https://developer.mozilla.org/en-US/docs/Web/API/URL.createObjectURL

Itu hanya akan mengunduh file di Chrome, Firefox dan Opera. Ini menggunakan atribut unduhan pada tag jangkar untuk memaksa browser untuk mengunduhnya.

JoshBerke
sumber
1
Tidak ada dukungan untuk atribut unduhan di IE dan Safari :( ( caniuse.com/#feat=download ). Anda dapat membuka jendela baru dan meletakkan konten di sana, tetapi tidak yakin tentang PDF atau Excel ...
Marçal Juan
1
Anda harus mengosongkan memori browser setelah menelepon click:window.URL.revokeObjectURL(link.href);
Edward Brey
@ JoshBerke Ini sudah tua tetapi berfungsi pada saya. Bagaimana saya bisa mendapatkannya untuk membuka direktori saya segera untuk menyimpan daripada menyimpan ke browser saya? Apakah ada cara untuk menentukan nama file yang masuk?
Jo Ko
2
Ini akan merusak file biner, karena mereka dapat dikonversi ke string menggunakan pengkodean, dan hasilnya tidak terlalu dekat dengan biner asli ...
Gobol
2
Dapat menggunakan mimetypes untuk tidak merusak informasi seperti yang digunakan di sini dengan PDF: alexhadik.com/blog/2016/7/7/l8ztp8kr5lbctf5qns4l8t3646npqh
Mateo Tibaquira
18

Saya tahu ini sudah lama, tapi saya pikir saya telah menemukan solusi yang lebih elegan. Saya memiliki masalah yang sama persis. Masalah yang saya hadapi dengan solusi yang disarankan adalah bahwa mereka semua memerlukan file yang disimpan di server, tetapi saya tidak ingin menyimpan file di server, karena memperkenalkan masalah lain (keamanan: file kemudian dapat diakses oleh pengguna yang tidak diautentikasi, pembersihan: bagaimana dan kapan Anda membuang file). Dan seperti Anda, data saya kompleks, objek JSON bersarang yang akan sulit dimasukkan ke dalam formulir.

Apa yang saya lakukan adalah membuat dua fungsi server. Yang pertama memvalidasi data. Jika ada kesalahan, itu akan dikembalikan. Jika itu bukan kesalahan, saya mengembalikan semua parameter serial / disandikan sebagai string base64. Kemudian, pada klien, saya memiliki formulir yang hanya memiliki satu input tersembunyi dan posting ke fungsi server kedua. Saya mengatur input tersembunyi ke string base64 dan mengirimkan format. Fungsi server kedua mendekode / deserializes parameter dan menghasilkan file. Formulir dapat dikirimkan ke jendela baru atau iframe pada halaman dan file akan terbuka.

Ada sedikit lebih banyak pekerjaan yang terlibat, dan mungkin sedikit lebih banyak pemrosesan, tetapi secara keseluruhan, saya merasa jauh lebih baik dengan solusi ini.

Kode dalam 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);
    }

pada klien

    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
sumber
1
Saya belum melihat solusi ini dengan baik, tetapi perlu dicatat bahwa tidak ada apa-apa tentang solusi menggunakan create_binary_file.php yang membutuhkan file untuk disimpan ke disk. Ini sepenuhnya layak untuk membuat create_binary_file.php menghasilkan file biner dalam memori.
SamStephens
11

Ada cara yang lebih sederhana, buat formulir dan posting, ini beresiko mengatur ulang halaman jika tipe mime pengembalian adalah sesuatu yang akan dibuka oleh browser, tetapi untuk csv dan semacamnya itu sempurna

Contoh membutuhkan garis bawah dan jquery

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

Untuk hal-hal seperti html, teks dan semacamnya, pastikan mimetype adalah sesuatu seperti application / octet-stream

kode php

<?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
sumber
8

Singkatnya, tidak ada cara yang lebih sederhana. Anda perlu membuat permintaan server lain untuk menampilkan file PDF. Meskipun, ada beberapa alternatif tetapi mereka tidak sempurna dan tidak akan berfungsi di semua browser:

  1. Lihatlah skema URI data . Jika data biner kecil, Anda mungkin dapat menggunakan javascript untuk membuka data yang lewat jendela di URI.
  2. Solusi Windows / IE saja akan memiliki .NET control atau FileSystemObject untuk menyimpan data pada sistem file lokal dan membukanya dari sana.
VinayC
sumber
Terima kasih, saya tidak mengetahui skema Data URI. Sepertinya itu mungkin satu-satunya cara untuk melakukannya dalam satu permintaan. Tetapi sebenarnya bukan arah yang ingin saya tuju.
Tauren
Karena persyaratan klien, saya akhirnya memecahkan masalah ini menggunakan header server di response ( Content-Disposition: attachment;filename="file.txt"), tapi saya benar-benar ingin mencoba pendekatan ini di lain waktu. Saya telah menggunakan URIdata untuk thumbnail sebelumnya, tetapi tidak pernah terpikir oleh saya untuk menggunakannya untuk unduhan - terima kasih telah berbagi nugget ini.
brichins
8

Sudah lama sejak pertanyaan ini diajukan tetapi saya memiliki tantangan yang sama dan ingin berbagi solusi. Ini menggunakan elemen dari jawaban lain tetapi saya tidak dapat menemukannya secara keseluruhan. Itu tidak menggunakan formulir atau iframe tetapi memang membutuhkan pasangan permintaan posting / dapatkan. Alih-alih menyimpan file di antara permintaan, itu menyimpan data posting. Tampaknya sederhana dan efektif.

klien

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
sumber
1
Saya pikir saya paling suka solusi ini. Dalam kasus saya, meskipun saya membuat file, jadi saya pikir saya akan mencoba menyimpan file dalam memori sampai diakses dan kemudian membebaskan memori setelah diunduh sehingga saya tidak perlu menulis ke disk.
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
sumber
3

Tidak sepenuhnya jawaban untuk posting asli, tetapi solusi cepat dan kotor untuk memposting objek json ke server dan secara dinamis menghasilkan unduhan.

Sisi klien 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();
}

..dan kemudian mendekode json-string di sisi server dan mengatur header untuk diunduh (contoh PHP):

$request = json_decode($_POST['jsonstring']), true);
header('Content-Type: application/csv');
header('Content-Disposition: attachment; filename=export.csv');
header('Pragma: no-cache');
ralftar
sumber
Saya suka solusi ini. Dalam pertanyaan OP, sepertinya pemohon tahu apakah mengharapkan pengunduhan file atau data JSON, sehingga ia dapat memutuskan di akhir klien dan memposting ke URL yang berbeda, daripada memutuskan di ujung server.
Sam
2

Saya pikir pendekatan terbaik adalah menggunakan kombinasi, pendekatan kedua Anda tampaknya menjadi solusi yang elegan di mana browser terlibat.

Jadi tergantung bagaimana panggilan itu dibuat. (baik itu browser atau panggilan layanan web), Anda dapat menggunakan kombinasi keduanya, dengan mengirim URL ke browser dan mengirim data mentah ke klien layanan web lainnya.

naikus
sumber
Pendekatan kedua saya terlihat lebih menarik bagi saya sekarang juga. Terima kasih telah mengkonfirmasi ini adalah solusi yang bermanfaat. Apakah Anda menyarankan agar saya memberikan nilai tambahan di objek json yang menunjukkan permintaan ini dibuat dari browser sebagai panggilan ajax alih-alih panggilan layanan web? Ada beberapa cara untuk mencapai hal ini yang dapat saya pikirkan, tetapi teknik apa yang akan Anda gunakan?
Tauren
tidak bisakah itu ditentukan oleh header http User-Agent? Atau header http lainnya?
naikus
1

Saya sudah bangun selama dua hari sekarang mencoba mencari cara untuk mengunduh file menggunakan jquery dengan panggilan ajax. Semua dukungan yang saya dapat tidak dapat membantu situasi saya sampai saya mencoba ini.

Sisi klien

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

}

Sisi server

 [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.
    }

Semoga berhasil.

Otis-iDev
sumber
2
Ini akan berfungsi, untuk file kecil. Tetapi jika Anda memiliki file besar Anda akan mengalami masalah url terlalu lama. Cobalah dengan 1.000 catatan, itu akan rusak dan hanya mengekspor sebagian dari data.
Michael Merrell
1

Sudah lama menemukannya di suatu tempat dan berfungsi dengan sempurna!

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

Pendekatan lain alih-alih menyimpan file di server dan mengambilnya, adalah dengan menggunakan .NET 4.0+ ObjectCache dengan kedaluwarsa singkat hingga Aksi kedua (saat itu dapat dibuang secara definitif). Alasan saya ingin menggunakan JQuery Ajax untuk melakukan panggilan, adalah karena tidak sinkron. Membangun file PDF dinamis saya membutuhkan waktu yang cukup lama, dan saya menampilkan dialog pemintal yang sibuk selama waktu itu (juga memungkinkan pekerjaan lain dilakukan). Pendekatan menggunakan data dikembalikan dalam "sukses:" untuk membuat gumpalan tidak berfungsi dengan baik. Itu tergantung pada konten file PDF. Mudah rusak oleh data dalam respons, jika tidak sepenuhnya tekstual yang bisa ditangani oleh Ajax.

Wray Smallwood
sumber
0

Larutan

Lampiran Content-Disposition tampaknya berfungsi untuk saya:

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

Penanganan masalah

application / octet-stream

Saya memiliki sesuatu yang serupa terjadi pada saya dengan JSON, bagi saya di sisi server saya sedang mengatur header ke self.set_header ("Content-Type", " application / json ") namun ketika saya mengubahnya menjadi:

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

Secara otomatis mengunduhnya.

Ketahuilah juga bahwa agar file tetap mempertahankan sufiks .json, Anda harus melakukannya pada header nama file:

self.set_header("Content-Disposition", 'filename=learned_data.json')
Bapak-Program
sumber
-1

Dengan HTML5, Anda bisa membuat jangkar dan mengkliknya. Tidak perlu menambahkannya ke dokumen sebagai seorang anak.

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

Semua selesai.

Jika Anda ingin memiliki nama khusus untuk unduhan tersebut, cukup kirimkan dalam downloadatribut:

const a = document.createElement('a');
a.download = 'my-special-name.pdf';
a.href = urlForPdfFile;
a.click();
ditulis ulang
sumber
4
pertanyaannya adalah tentang metode POST
dovid