Загрузить файл с помощью запроса ajax

Я хочу отправить "запрос загрузки ajax", когда я нажимаю кнопку, поэтому я попытался таким образом:

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

но не работает должным образом, как я могу это сделать? Заранее благодарю

Ответ 1

Обновление 27 апреля 2015 г.

Вверх и переход на сцену HTML5 - это атрибут . Он поддерживается в Firefox и Chrome, и скоро появится IE11. В зависимости от ваших потребностей вы можете использовать его вместо запроса AJAX (или используя window.location), если файл, который вы хотите загрузить, находится в том же месте, что и ваш сайт.

Вы всегда можете сделать запрос AJAX/ window.location резервным, используя некоторый JavaScript, чтобы проверить, поддерживается ли download, а если нет, переключая его на вызов window.location.

Оригинальный ответ

У вас не может быть запрос AJAX, чтобы открыть приглашение загрузки, так как вам физически приходится перемещаться по файлу, чтобы запросить загрузку. Вместо этого вы можете использовать функцию успеха, чтобы перейти к download.php. Это откроет приглашение загрузки, но не изменит текущую страницу.

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

Даже если это отвечает на вопрос, лучше просто использовать window.location и полностью исключить запрос AJAX.

Ответ 2

Для этого вам вообще не нужен ajax. Если вы просто установите "download.php" как href на кнопке или, если это не ссылка, используйте:

window.location = 'download.php';

Браузер должен распознавать двоичную загрузку и не загружать фактическую страницу, а просто обслуживать файл как загрузку.

Ответ 3

Чтобы браузер загрузил файл, вам необходимо сделать такой запрос:

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

Ответ 4

Это возможно. Вы можете загрузить загрузку изнутри функции ajax, например, сразу после создания файла .csv.

У меня есть функция ajax, которая экспортирует базу данных контактов в CSV файл, и сразу после ее завершения автоматически запускает загрузку файла .csv. Итак, после получения ответаText, и все в порядке, я перенаправляю браузер следующим образом:

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

Мой файл download.php выглядит следующим образом:

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

?>

Нет обновления страницы, и файл автоматически загружается.

ПРИМЕЧАНИЕ. Протестировано в следующих браузерах:

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

Ответ 5

Кросс-браузерное решение, протестированное на Chrome, Firefox, Edge, IE11.

В DOM добавьте тег скрытой ссылки:

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

Затем:

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

Ответ 7

Декодирование имени файла из заголовка немного сложнее...

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

Ответ 8

Это решение не сильно отличается от приведенного выше, но для меня это работает очень хорошо, и я думаю, что он чист.

Я предлагаю base64 кодировать сторону файлового сервера (base64_encode(), если вы используете PHP) и отправлять данные с кодировкой base64 клиенту

На клиенте вы делаете это:

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

Этот код помещает закодированные данные в ссылку и имитирует щелчок по ссылке, а затем удаляет ее.

Ответ 9

Ваши потребности покрыты window.location('download.php');
Но я думаю, что вам нужно передать файл для загрузки, не всегда загружать один и тот же файл, и поэтому, почему вы используете запрос, один из вариантов - создать файл php, такой же простой, как showfile.php, и выполнить запрос, подобный

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

showfile.php

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

где file - это имя файла, переданное через Get или Post в запросе, а затем просто перехватывает ответ в функции

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

Ответ 10

Это может быть поздно, но это может помочь кому-то, кто сталкивается с этим.

Примечание: это не прямой ответ. Это альтернативный способ.

Во-первых, создайте скрытый элемент привязки, цель которого пуста, чтобы открыть ссылку в новом окне.

<a id="hidden-permalink" class="hidden" href="javascript:void(0)" target="_blank">Hidden</a>

Во-вторых, из вашего успешного обратного вызова ajax/javascript. Получите доступ к скрытому тегу привязки и установите новый URL, а затем активируйте его, как будто пользователь обычно щелкает по нему

success: function ( response ) {
  $( '#hidden-permalink' ).attr( 'href', response.permalink )[0].click();
}

Спасибо

Ответ 11

есть другое решение для загрузки веб-страницы в ajax. Но я имею в виду страницу, которая должна быть сначала обработана, а затем загружена.

Для начала нужно отделить обработку страницы от загрузки результатов.

1) В вызове ajax выполняются только расчеты страницы.

$.post("CalculusPage.php", { calculusFunction: true, ID: 29, data1: "a", data2: "b" },

       function(data, status) 
       {
            if (status == "success") 
            {
                /* 2) In the answer the page that uses the previous calculations is downloaded. For example, this can be a page that prints the results of a table calculated in the ajax call. */
                window.location.href = DownloadPage.php+"?ID="+29;
            }               
       }
);

// For example: in the CalculusPage.php

    if ( !empty($_POST["calculusFunction"]) ) 
    {
        $ID = $_POST["ID"];

        $query = "INSERT INTO ExamplePage (data1, data2) VALUES ('".$_POST["data1"]."', '".$_POST["data2"]."') WHERE id = ".$ID;
        ...
    }

// For example: in the DownloadPage.php

    $ID = $_GET["ID"];

    $sede = "SELECT * FROM ExamplePage WHERE id = ".$ID;
    ...

    $filename="Export_Data.xls";
    header("Content-Type: application/vnd.ms-excel");
    header("Content-Disposition: inline; filename=$filename");

    ...

Я надеюсь, что это решение может быть полезным для многих, как и для меня.