web-dev-qa-db-fra.com

télécharger le fichier en utilisant une requête ajax

Je souhaite envoyer une "demande de téléchargement ajax" lorsque je clique sur un bouton. J'ai donc essayé de cette manière:

javascript:

var xhr = new XMLHttpRequest();
xhr.open("GET", "download.php");
xhr.send();

download.php:

<?
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename= file.txt");
header("Content-Transfer-Encoding: binary");    
readfile("file.txt");
?>

mais ne fonctionne pas comme prévu, comment puis-je faire? Merci d'avance

74
Manuel Di Iorio

Mise à jour du 27 avril 2015

L'attribut download . C'est supporté dans Firefox et Chrome, et bientôt sur IE11. Selon vos besoins, vous pouvez l'utiliser au lieu d'une requête AJAX (ou à l'aide de window.location) tant que le fichier que vous souhaitez télécharger se trouve sur la même origine que votre site.

Vous pouvez toujours utiliser la demande AJAX/window.location comme solution de secours en utilisant some JavaScript pour tester si download est pris en charge et, dans le cas contraire, le basculer vers l'appel window.location.

Réponse originale

Vous ne pouvez pas avoir une demande AJAX ouvrir l'invite de téléchargement car vous devez accéder physiquement au fichier pour demander le téléchargement. Au lieu de cela, vous pouvez utiliser une fonction de réussite pour accéder à download.php. Cela ouvrira l'invite de téléchargement mais ne changera pas la page actuelle.

$.ajax({
    url: 'download.php',
    type: 'POST',
    success: function() {
        window.location = 'download.php';
    }
});

Même si cela répond à la question, il vaut mieux utiliser window.location et éviter complètement la requête AJAX.

90
Steven Lambert

En fait, vous n'avez pas du tout besoin d'ajax pour cela. Si vous définissez simplement "download.php" comme href sur le bouton, ou si ce n'est pas un lien, utilisez:

window.location = 'download.php';

Le navigateur doit reconnaître le téléchargement binaire et ne pas charger la page réelle, mais simplement servir le fichier en tant que téléchargement.

38
Jelle Kralt

Pour que le navigateur télécharge un fichier, vous devez faire la demande comme ça:

 function downloadFile(urlToSend) {
     var req = new XMLHttpRequest();
     req.open("GET", urlToSend, true);
     req.responseType = "blob";
     req.onload = function (event) {
         var blob = req.response;
         var fileName = req.getResponseHeader("fileName") //if you have the fileName header available
         var link=document.createElement('a');
         link.href=window.URL.createObjectURL(blob);
         link.download=fileName;
         link.click();
     };

     req.send();
 }
18
João Marcos

C'est possible. Vous pouvez faire démarrer le téléchargement depuis une fonction ajax, par exemple, juste après la création du fichier .csv.

J'ai une fonction ajax qui exporte une base de données de contacts dans un fichier .csv, et juste après qu'elle se termine, le téléchargement du fichier .csv démarre automatiquement. Donc, après avoir obtenu le responseText et que tout est ok, je redirige le navigateur de la manière suivante:

window.location="download.php?filename=export.csv";

Mon fichier download.php ressemble à ceci:

<?php

    $file = $_GET['filename'];

    header("Cache-Control: public");
    header("Content-Description: File Transfer");
    header("Content-Disposition: attachment; filename=".$file."");
    header("Content-Transfer-Encoding: binary");
    header("Content-Type: binary/octet-stream");
    readfile($file);

?>

Il n'y a aucune actualisation de la page et le téléchargement du fichier commence automatiquement. 

NOTE- Testé dans les navigateurs suivants:

Chrome v37.0.2062.120 
Firefox v32.0.1
Opera v12.17
Internet Explorer v11
13
Pedro Sousa

Solution multi-navigateurs testée sur Chrome, Firefox, Edge, IE11.

Dans le DOM, ajoutez une balise de lien masqué:

<a id="target" style="display: none"></a>

Ensuite:

var req = new XMLHttpRequest();
req.open("GET", downloadUrl, true);
req.responseType = "blob";

req.onload = function (event) {
  var blob = req.response;
  var fileName = null;
  var contentType = req.getResponseHeader("content-type");

  // IE/Edge seems not returning some response header
  if (req.getResponseHeader("content-disposition")) {
    var contentDisposition = req.getResponseHeader("content-disposition");
    fileName = contentDisposition.substring(contentDisposition.indexOf("=")+1);
  } else {
    fileName = "unnamed." + contentType.substring(contentType.indexOf("/")+1);
  }

  if (window.navigator.msSaveOrOpenBlob) {
    // Internet Explorer
    window.navigator.msSaveOrOpenBlob(new Blob([blob], {type: contentType}), fileName);
  } else {
    var el = document.getElementById("target");
    el.href = window.URL.createObjectURL(blob);
    el.download = fileName;
    el.click();
  }
};
req.send();
9
leo

Je préfère location.assign(url);

Exemple de syntaxe complète:

document.location.assign('https://www.urltodocument.com/document.pdf');

developer.mozilla.org/en-US/docs/Web/API/Location.assign

2
Telmo Dias

Vos besoins sont couverts par window.location('download.php');
Mais je pense que vous devez transmettre le fichier à télécharger, pas toujours télécharger le même fichier, et c’est pourquoi vous utilisez une requête. Une option consiste à créer un fichier php aussi simple que showfile.php et faire une demande comme

var myfile = filetodownload.txt
var url = "shofile.php?file=" + myfile ;
ajaxRequest.open("GET", url, true);

showfile.php

<?php
$file = $_GET["file"] 
echo $file;

où fichier est le nom du fichier transmis via Get ou Post dans la demande, puis intercepte la réponse dans une fonction simplement

if(ajaxRequest.readyState == 4){
                        var file = ajaxRequest.responseText;
                        window.location = 'downfile.php?file=' + file;  
                    }
                }
0
lisandro

Cette solution n’est pas très différente de celle ci-dessus, mais pour moi cela fonctionne très bien et je pense que c’est propre.

Je suggère de coder en base64 le côté serveur de fichiers (base64_encode (), si vous utilisez PHP) et d'envoyer les données codées en base64 au client

Sur le client, vous faites ceci:

 let blob = this.dataURItoBlob(THE_MIME_TYPE + "," + response.file);
 let uri = URL.createObjectURL(blob);
 let link = document.createElement("a");
 link.download = THE_FILE_NAME,
 link.href = uri;
 document.body.appendChild(link);
 link.click();
 document.body.removeChild(link);

Ce code place les données codées dans un lien et simule un clic sur le lien, puis les supprime.

0
Kapalua

il existe une autre solution pour télécharger une page Web en ajax. Mais je me réfère à une page qui doit d’abord être traitée puis téléchargée.

Vous devez d’abord séparer le traitement de la page du téléchargement des résultats.

1) Seuls les calculs de page sont effectués dans l'appel ajax.

 $. post ("CalculusPage.php", {calculusFunction: true, ID: 29, data1: "a", data2: "b"}, 
 
 fonction (data , statut) 
 {
 if (status == "succès") 
 {
/* 2) Dans la réponse, la page qui utilise les calculs précédents est téléchargée . Par exemple, il peut s'agir d'une page imprimant les résultats d'une table calculée dans l'appel ajax. */
 window.location.href = DownloadPage.php + "? ID =" + 29; 
} 
} 
); 
 
 // Par exemple: dans la page de calcul.php 
 
 If (! Empty ($ _ POST ["calculusFunction"])) 
 {
 $ ID = $ _POST ["ID"]; 
 
 $ Query = "INSERT INTO ExamplePage (data1, data2) VALEURS ('". $ _ POST ["data1"]. "'," ". $ _POST ["data2"]. "') WHERE id =". $ ID; 
 ... 
} 
 
 // Par exemple: dans le DownloadPage.php 
 
 $ ID = $ _GET ["ID"]; 
 
 $ Sede = "SELECT * FROM ExemplePage WHERE id =". $ ID; 
 ... 
 
 $ filename = "Export_Data.xls"; 
 en-tête ("Content-Type: application/vnd.ms-Excel"); 
 en-tête ("Content-Disposition: inline; nomfichier = $ nomfichier"); 
 
 ... 

J'espère que cette solution pourra être utile pour beaucoup comme pour moi.

0
netluke

Décoder un nom de fichier à partir de l'en-tête est un peu plus complexe ...

    var filename = "default.pdf";
    var disposition = req.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, '');
    }
0
Lumic