web-dev-qa-db-ja.com

ajaxリクエストを使ってファイルをダウンロードする

ボタンをクリックしたときに "ajax download request"を送信したいので、このようにして試しました。

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

しかし、期待どおりに動作しません、どうすればいいですか。前もって感謝します

83
Manuel Di Iorio

更新2015年4月27日

HTML5の登場は、 download attribute です。 FirefoxとChromeでは supported 、そしてもうすぐIE11になるでしょう。あなたのニーズによっては、ダウンロードしたいファイルがあなたのサイトと同じOrigin上にある限り、AJAXリクエストの代わりに(あるいはwindow.locationを使う)使うことができます。

some JavaScript を使用してdownloadがサポートされているかどうかをテストし、サポートされていない場合はwindow.locationを呼び出すように切り替えることで、常にAJAX request/window.locationを代替として使用できます。

元の答え

AJAX要求でダウンロードプロンプトを開くことはできません。ダウンロードを促すにはファイルに移動する必要があるためです。代わりに、成功関数を使用してdownload.phpに移動することができます。これによりダウンロードプロンプトが開きますが、現在のページは変更されません。

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

これは質問に答えますが、window.locationを使用し、AJAXリクエストを完全に回避することをお勧めします。

86
Steven Lambert

これには実際にはajaxはまったく必要ありません。ボタンのhrefとして "download.php"を設定しただけの場合、またはリンクでない場合は次のようにします。

window.location = 'download.php';

ブラウザはバイナリダウンロードを認識し、実際のページをロードするのではなく、単にダウンロードとしてファイルを提供するべきです。

39
Jelle Kralt

ブラウザにファイルをダウンロードさせるには、次のようにリクエストする必要があります。

 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();
 }
32
João Marcos

クロスブラウザソリューション、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();
14
leo

可能です。たとえば、.csvファイルが作成された直後など、ajax関数内からダウンロードを開始できます。

連絡先のデータベースを.csvファイルにエクスポートするajax関数があり、それが完了すると自動的に.csvファイルのダウンロードが開始されます。だから、私はresponseTextを取得し、すべてがOKであった後、私はこのようにブラウザをリダイレクトします:

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

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

?>

ページの更新はまったく行われず、ファイルは自動的にダウンロードを開始します。

NOTE - 以下のブラウザでテスト済み。

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

私はlocation.assign(url);が好きです

完全な構文例:

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

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

3
Telmo Dias

あなたのニーズはwindow.location('download.php');でカバーされています
しかし、いつも同じファイルをダウンロードするのではなく、ダウンロードするファイルを渡す必要があると思います。リクエストを使用している理由の1つは、showfile.phpと同じくらい簡単な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;  
                    }
                }
0
lisandro

この解決策は上記のものとそれほど違いはありませんが、私にとっては非常にうまく機能していて、私はそれがきれいだと思います。

私は、ファイルサーバー側(base64_encode()、PHPを使用している場合)をbase64エンコードし、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);

このコードは、エンコードされたデータをリンクに配置してリンクのクリックをシミュレートしてから削除します。

0
martinethyl

ajaxでWebページをダウンロードするための別の解決策があります。しかし、最初に処理してからダウンロードする必要があるページを参照しています。

まず、ダウンロード結果からページ処理を切り離す必要があります。

1)ajax呼び出しではページ計算のみが行われます。

 $。post( "CalculusPage.php"、{calculus関数:true、ID:29、data1: "a"、data2: "b"}、
 
 function(data 、status)
 {
 if(status == "success")
 {
/* 2)答えとして、前の計算を使ったページがダウンロードされます。 。例えば、これはajax呼び出しで計算された表の結果を印刷するページにすることができます。 */
 window.location.href = DownloadPage.php + "?ID =" + 29; 
} 
} 
); 
 [。 //例:CalculusPage.php 
 
 if(!empty($ _ POST ["calculusFunction"]))
 {
 $ ID = $ _POST ["ID"]; 
 
 $ query = "ExamplePage(data1、data2)の値に挿入する値( '"。$ _ POST ["data1"]。 "'、 '"。 $ _POST ["data2"]。 "')WHERE id ="。$ ID; 
 ... 
} 
 
 //たとえば、 DownloadPage.php 
 
 $ ID = $ _GET ["ID"]; 
 
 $ sede = "例* WHERE id ="。$ ID; 
 ... 
 
 $ filename = "Export_Data.xls"; 
ヘッダー( "Content-Type:application/vnd.ms-Excel"); [ header( "Content-Disposition:inline; filename = $ filename"); 
 
 ... 

私にとってこの解決策が多くの人に役立つことを願っています。

0
netluke

ヘッダからファイル名をデコードするのはもう少し複雑です...

    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