ajaxポストからのファイルのダウンロードを処理する


393

特定のURLにajax POSTリクエストを送信するJavaScriptアプリがあります。応答は、JSON文字列の場合もあれば、ファイル(添付ファイルとして)の場合もあります。ajax呼び出しでContent-TypeとContent-Dispositionを簡単に検出できますが、応答にファイルが含まれていることを検出したら、クライアントにダウンロードを提供するにはどうすればよいですか?ここでは類似のスレッドをいくつか読みましたが、どれも私が探している答えを提供していません。

これにはajaxを使用しない、またはブラウザをリダイレクトする必要があることを示唆する回答を投稿しないでください。これはいずれもオプションではないためです。プレーンHTMLフォームの使用もオプションではありません。クライアントにダウンロードダイアログを表示する必要があります。これを行うことはできますか?


この記事を読んでいる人のために、この記事をお読みください。stackoverflow.com/questions/20830309/...
ソブハン

質問からソリューションを削除しました。以下の回答投稿として投稿していただけますが、質問投稿には含まれません。
Martijn Pieters

回答:


111

フォームを作成し、POSTメソッドを使用してフォームを送信します。iframeは必要ありません。サーバーページがリクエストに応答したら、ファイルのMIMEタイプのレスポンスヘッダーを記述します。これにより、ダウンロードダイアログが表示されます-これを何度も行いました。

コンテンツタイプのアプリケーション/ダウンロードが必要な場合-使用している言語のダウンロードを提供する方法を検索してください。


35
質問で述べたように、「プレーンHTMLフォームの使用もオプションではありません。」
Pavle Predic 2013

13
いいえ。通常のPOSTを使用すると、ブラウザがPOST URLに移動するためです。ページから移動したくありません。リクエストをバックグラウンドで実行し、レスポンスを処理してクライアントに提示したい。
Pavle Predic 2013

6
サーバーが他の回答のようにヘッダーを返信する場合、新しいウィンドウで開きます-以前に行ったことがあります。サーバー側のスクリプトがHTMLコードを返した場合にのみ移動します

1
@PavlePredicは、JSONテキスト応答またはダウンロードファイル応答など、両方の応答シナリオを管理する方法を理解することになりましたか?
Webユーザー、

9
答えは明確ではなく、提案されたソリューションは機能しません。
stack247

531

FileAPIの一部を使用してこれを(最新のブラウザーで)行うことができるため、それほどあきらめないでください。

var xhr = new XMLHttpRequest();
xhr.open('POST', url, true);
xhr.responseType = 'arraybuffer';
xhr.onload = function () {
    if (this.status === 200) {
        var filename = "";
        var disposition = xhr.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, '');
        }
        var type = xhr.getResponseHeader('Content-Type');

        var blob;
        if (typeof File === 'function') {
            try {
                blob = new File([this.response], filename, { type: type });
            } catch (e) { /* Edge */ }
        }
        if (typeof blob === 'undefined') {
            blob = new Blob([this.response], { type: type });
        }

        if (typeof window.navigator.msSaveBlob !== 'undefined') {
            // IE workaround for "HTML7007: One or more blob URLs were revoked by closing the blob for which they were created. These URLs will no longer resolve as the data backing the URL has been freed."
            window.navigator.msSaveBlob(blob, filename);
        } else {
            var URL = window.URL || window.webkitURL;
            var downloadUrl = URL.createObjectURL(blob);

            if (filename) {
                // use HTML5 a[download] attribute to specify filename
                var a = document.createElement("a");
                // safari doesn't support this yet
                if (typeof a.download === 'undefined') {
                    window.location.href = downloadUrl;
                } else {
                    a.href = downloadUrl;
                    a.download = filename;
                    document.body.appendChild(a);
                    a.click();
                }
            } else {
                window.location.href = downloadUrl;
            }

            setTimeout(function () { URL.revokeObjectURL(downloadUrl); }, 100); // cleanup
        }
    }
};
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhr.send($.param(params));

これはjQuery.ajaxを使用した古いバージョンです。応答がなんらかの文字セットの文字列に変換されると、バイナリデータが破損する場合があります。

$.ajax({
    type: "POST",
    url: url,
    data: params,
    success: function(response, status, xhr) {
        // check for a filename
        var filename = "";
        var disposition = xhr.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, '');
        }

        var type = xhr.getResponseHeader('Content-Type');
        var blob = new Blob([response], { type: type });

        if (typeof window.navigator.msSaveBlob !== 'undefined') {
            // IE workaround for "HTML7007: One or more blob URLs were revoked by closing the blob for which they were created. These URLs will no longer resolve as the data backing the URL has been freed."
            window.navigator.msSaveBlob(blob, filename);
        } else {
            var URL = window.URL || window.webkitURL;
            var downloadUrl = URL.createObjectURL(blob);

            if (filename) {
                // use HTML5 a[download] attribute to specify filename
                var a = document.createElement("a");
                // safari doesn't support this yet
                if (typeof a.download === 'undefined') {
                    window.location.href = downloadUrl;
                } else {
                    a.href = downloadUrl;
                    a.download = filename;
                    document.body.appendChild(a);
                    a.click();
                }
            } else {
                window.location.href = downloadUrl;
            }

            setTimeout(function () { URL.revokeObjectURL(downloadUrl); }, 100); // cleanup
        }
    }
});

1
どうもありがとう !ただし、HTTPレスポンスの「Access-Control-Expose-Headers」と「Access-Control-Allow-Headers」の両方に「Content-disposition」を追加して機能させる必要がありました。
JulienD 2016

1
ファイルが500 mbより大きい場合は機能しません。別のAPIを使用する必要がありますか?
hirra 2016年

クリーンアップ部分(URLだけでなく)のDOMからa要素を削除するのはどうですか?document.body.removeChild(a);
スコアグラフィック

@hirra代わりに"arraybuffer"の使用responceType "ブロブ"をおよび方法は、そのVaRのブロブがthis.responseあることのonloadコールバック関数を書き換える(VAR BLOB = this.response;)そうvar blob =this.responce; /** if (typeof File === 'function') { try { blob = new File([this.response], filename, { type: type }); } catch (e) { /* Edge */ } } if (typeof blob === 'undefined') { blob = new Blob([this.response], { type: type }); } */
クリスTobba

1
これは完璧なソリューションです。ほんの小さな変更。活字体では、私は必要なwindow.location.href = downloadUrlの代わりにwindow.location = downloadUrl
michal.jakubeczy

39

私は同じ問題に直面し、それを首尾よく解決しました。私のユースケースはこれです。

" サーバーにJSONデータを送信してExcelファイルを受信します。そのExcelファイルはサーバーによって作成され、クライアントへの応答として返されます。その応答をカスタム名のファイルとしてブラウザーにダウンロードしてください "

$("#my-button").on("click", function(){

// Data to post
data = {
    ids: [1, 2, 3, 4, 5]
};

// Use XMLHttpRequest instead of Jquery $ajax
xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
    var a;
    if (xhttp.readyState === 4 && xhttp.status === 200) {
        // Trick for making downloadable link
        a = document.createElement('a');
        a.href = window.URL.createObjectURL(xhttp.response);
        // Give filename you wish to download
        a.download = "test-file.xls";
        a.style.display = 'none';
        document.body.appendChild(a);
        a.click();
    }
};
// Post data to URL which handles post request
xhttp.open("POST", excelDownloadUrl);
xhttp.setRequestHeader("Content-Type", "application/json");
// You should set responseType as blob for binary responses
xhttp.responseType = 'blob';
xhttp.send(JSON.stringify(data));
});

上記のスニペットは次のようにしています

  • XMLHttpRequestを使用してサーバーに配列をJSONとして投稿する。
  • コンテンツをblob(バイナリ)としてフェッチした後、ダウンロード可能なURLを作成し、それを非表示の「a」リンクに添付してクリックします。

ここでは、サーバー側で慎重にいくつかの設定を行う必要があります。Python Django HttpResponseにいくつかのヘッダーを設定しました。他のプログラミング言語を使用する場合は、それに応じて設定する必要があります。

# In python django code
response = HttpResponse(file_content, content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")

ここでxls(excel)をダウンロードしたので、contentTypeを上記の1に調整しました。ファイルタイプに応じて設定する必要があります。この手法を使用して、あらゆる種類のファイルをダウンロードできます。


33

どのサーバー側の言語を使用していますか?私のアプリでは、PHPの応答に正しいヘッダーを設定することで、AJAX呼び出しからファイルを簡単にダウンロードできます。

サーバー側のヘッダーの設定

header("HTTP/1.1 200 OK");
header("Pragma: public");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");

// The optional second 'replace' parameter indicates whether the header
// should replace a previous similar header, or add a second header of
// the same type. By default it will replace, but if you pass in FALSE
// as the second argument you can force multiple headers of the same type.
header("Cache-Control: private", false);

header("Content-type: " . $mimeType);

// $strFileName is, of course, the filename of the file being downloaded. 
// This won't have to be the same name as the actual file.
header("Content-Disposition: attachment; filename=\"{$strFileName}\""); 

header("Content-Transfer-Encoding: binary");
header("Content-Length: " . mb_strlen($strFile));

// $strFile is a binary representation of the file that is being downloaded.
echo $strFile;

これは実際にはブラウザーをこのダウンロードページに「リダイレクト」しますが、@ ahrenがコメントですでに述べたように、現在のページから移動することはありません。

すべてが正しいヘッダーを設定することなので、PHPでない場合は、使用しているサーバー側の言語に適した解決策が見つかるはずです。

応答クライアント側の処理

AJAX呼び出しを行う方法をすでに知っていると仮定して、クライアント側でサーバーへのAJAX要求を実行します。次に、サーバーは、このファイルをダウンロードできる場所からリンクを生成します。たとえば、ポイントしたい「転送」URLです。たとえば、サーバーは次のように応答します。

{
    status: 1, // ok
    // unique one-time download token, not required of course
    message: 'http://yourwebsite.com/getdownload/ska08912dsa'
}

応答を処理するときiframeは、本文にを挿入し、iframeのSRCを次のように受信したURLに設定します(この例を簡単にするためにjQueryを使用します)。

$("body").append("<iframe src='" + data.message +
  "' style='display: none;' ></iframe>");

上記のように正しいヘッダーを設定した場合、iframeはブラウザーを現在のページから移動せずにダウンロードダイアログを強制します。

注意

あなたの質問に関連して追加の追加; AJAXテクノロジーで何かを要求するときは常にJSONを返すのが最善だと思います。JSON応答を受け取ったら、クライアント側でそれをどうするかを決定できます。たとえば、後でユーザーにダウンロードを直接強制するのではなく、URLへのダウンロードリンクをクリックさせたい場合は、現在の設定でクライアント側とサーバー側の両方を更新する必要があります。


24

Angularの観点からソリューションを探している人にとって、これは私にとってうまくいきました:

$http.post(
  'url',
  {},
  {responseType: 'arraybuffer'}
).then(function (response) {
  var headers = response.headers();
  var blob = new Blob([response.data],{type:headers['content-type']});
  var link = document.createElement('a');
  link.href = window.URL.createObjectURL(blob);
  link.download = "Filename";
  link.click();
});

これは役に立ちましたが、元のファイル名を保持する必要があります。"Content-Disposition"の応答ヘッダーにファイル名が表示されていますが、コードの応答オブジェクトでその値を見つけることができません。設定link.download = ""するとランダムなGUIDファイル名が生成され、link.download = null「null」という名前のファイルが生成されます。
マリー

@Marie、INPUT要素のHTMLInputElement.filesプロパティを使用して、アップロード時のファイル名を記録できます。詳細については、ファイル入力に関するMDNドキュメントを参照してください。
Tim Hettler

Blobサイズが制限されます。stackoverflow.com/questions/28307789/...
user0800

22

これが私がこれをどのように機能させるかです https://stackoverflow.com/a/27563953/2845977

$.ajax({
  url: '<URL_TO_FILE>',
  success: function(data) {
    var blob=new Blob([data]);
    var link=document.createElement('a');
    link.href=window.URL.createObjectURL(blob);
    link.download="<FILENAME_TO_SAVE_WITH_EXTENSION>";
    link.click();
  }
});

download.jsを使用した回答の更新

$.ajax({
  url: '<URL_TO_FILE>',
  success: download.bind(true, "<FILENAME_TO_SAVE_WITH_EXTENSION>", "<FILE_MIME_TYPE>")
});


ありがとう、今日使ったばかり。ファンタスティック
ライアンウィルソン

こんにちは、jQuery 3.0が必要です>これを機能させるには?
gbade_

私はまた、あなたが与えた両方の例で空白のpdfを取得しています。PDFファイルをダウンロードできるようにしています。
gbade_

@gbade_いいえ、特定のjQueryバージョンは必要ありません。すべてのバージョンで正常に動作するはずです。ダウンロードするPDFに正しいCORSヘッダーがあるかどうかを確認しましたか?コンソールのエラーはデバッグに役立つかもしれません
Mayur Padshala

これはdownload.jsを使用して私のために働きました:success: function (response, status, request) { download(response, "filename.txt", "application/text"); }
Sga

12

あなたはすでに解決策を見つけたようですが、大きなPOSTリクエストで同じことを達成しようとしている人を助けるいくつかの情報を追加したかっただけです。

私は確かにAJAXを通じて「クリーン」のダウンロードを達成することは不可能である、数週間前に同じ問題を持っていた、フィラメントグループが既に判明しました正確にどのように動作するjQueryプラグインを作成し、それが呼び出されたjQueryのファイルダウンロードは、しかし、この手法の欠点はあります。

AJAXを介して大きなリクエストを送信している場合(ファイル+ 1MBなど)、応答性に悪影響を及ぼします。遅いインターネット接続では、リクエストが送信されるまでかなり待たなければならず、ファイルがダウンロードされるのを待つ必要もあります。「クリック」=>「ポップアップ」=>「ダウンロード開始」のようなものではありません。「クリック」=>「データが送信されるまで待機する」=>「応答を待機する」=>「ダウンロードの開始」に似ています。これにより、要求が送信されるまで待機する必要があるため、ファイルのサイズが2倍になります。 AJAXを介してダウンロード可能なファイルとして取得します。

1MB未満の小さなファイルサイズで作業している場合、これに気付かないでしょう。しかし、自分のアプリで発見したように、ファイルサイズが大きい場合は、ほとんど耐えられません。

私のアプリでは、ユーザーが動的に生成された画像をエクスポートできるようにしています。これらの画像は、base64形式のPOSTリクエストを通じてサーバーに送信され(これが唯一の可能な方法です)、処理され、.png、.jpgファイル、base64の形式でユーザーに送信されます。画像の文字列+ 1MBは巨大です。これにより、ユーザーはファイルのダウンロードが開始されるまで必要以上に待たされることになります。遅いインターネット接続では、それは本当に迷惑なことがあります。

これに対する私の解決策は、サーバーにファイルを一時的に書き込み、準備ができたら、「お待ちください...」と「ダウンロード」の状態が同時に変化するボタンの形式でファイルへのリンクを動的に生成することでした。次に、base64イメージをプレビューポップアップウィンドウに印刷して、ユーザーが「右クリック」して保存できるようにします。これにより、すべての待機時間がユーザーにとって耐えられるようになり、速度も向上します。

2014年9月30日更新:

これを投稿してから数か月が経過しましたが、大きなbase64文字列を処理する場合に、速度を上げるためのより良いアプローチが見つかりました。データベースにbase64文字列を(ロングテキストまたはロングブログフィールドを使用して)保存し、そのレコードIDをjQuery File Downloadに渡し、最後にダウンロードスクリプトファイルでこのIDを使用してデータベースにクエリを実行し、base64文字列をプルして渡しますダウンロード機能。

スクリプトの例をダウンロード:

<?php
// Record ID
$downloadID = (int)$_POST['id'];
// Query Data (this example uses CodeIgniter)
$data       = $CI->MyQueries->GetDownload( $downloadID );
// base64 tags are replaced by [removed], so we strip them out
$base64     = base64_decode( preg_replace('#\[removed\]#', '', $data[0]->image) );
// This example is for base64 images
$imgsize    = getimagesize( $base64 );
// Set content headers
header('Content-Disposition: attachment; filename="my-file.png"');
header('Content-type: '.$imgsize['mime']);
// Force download
echo $base64;
?>

これはOPが要求したものをはるかに超えていることはわかっていますが、自分の調査結果で回答を更新するのは良いことだと感じました。私が問題の解決策を探していたとき、「AJAX POSTデータからのダウンロード」スレッドをたくさん読んだので、探していた答えが得られませんでした。この情報が、このようなことを達成しようとしている人に役立つことを願っています。


jQuery File DownloadURLのみに私をリダイレクトします。私はこれを次のように呼びますjQuery.download("api/ide/download-this-file.php", {filePath: path2Down}, "POST");
キャスパー

5

受け入れられた回答でテクニックを使用するときに発生するいくつかの問題、つまりフォームポストの使用を指摘したいと思います。

  1. リクエストにヘッダーを設定することはできません。認証スキーマにヘッダーが含まれる場合、Authorizationヘッダーで渡されるJson-Web-Tokenは、それを送信する別の方法(クエリパラメーターなど)を見つける必要があります。

  2. リクエストがいつ終了したかは、実際にはわかりません。まあ、jquery.fileDownloadによって行われるように、応答時に設定されるCookieを使用できますが、これは完全にFARです。同時リクエストでは機能せず、応答が届かない場合は機能しません。

  3. サーバーがエラーで応答した場合、ユーザーはエラーページにリダイレクトされます。

  4. フォームでサポートされているコンテンツタイプのみを使用できます。つまり、JSONは使用できません。

S3でファイルを保存し、事前に署名されたURLを送信してファイルを取得する方法を使用してしまいました。


5

よりモダンなアプローチをお探しの方は、を使用できますfetch API。次の例は、スプレッドシートファイルをダウンロードする方法を示しています。以下のコードで簡単にできます。

fetch(url, {
    body: JSON.stringify(data),
    method: 'POST',
    headers: {
        'Content-Type': 'application/json; charset=utf-8'
    },
})
.then(response => response.blob())
.then(response => {
    const blob = new Blob([response], {type: 'application/application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'});
    const downloadUrl = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = downloadUrl;
    a.download = "file.xlsx";
    document.body.appendChild(a);
    a.click();
})

このアプローチは他のXMLHttpRequestソリューションよりもはるかに理解しやすいと思います。また、これは、jQueryアプローチに追加のライブラリを追加する必要はありません。

もちろん、この新しいアプローチはIEでは機能しないので、開発中のブラウザーを確認することをお勧めします。ブラウザの完全な互換性リストは、次の[リンク] [1]にあります。

重要:この例では、指定されたをリッスンしているサーバーにJSONリクエストを送信していますurl。これurlは設定する必要があります。私の例では、この部分を知っていると想定しています。また、リクエストが機能するために必要なヘッダーについても検討してください。私はJSONを送信しているので、受信するリクエストのタイプをサーバーに知らせるContent-Typeためにapplication/json; charset=utf-8、ヘッダーを追加してに設定する必要があります。


1
驚くばかり!これをダウンロードポップアップの代わりに新しいタブで開くには、 `` `const window = open(downloadUrl、" _blank ");を使用します。if(window!== null)window.focus(); `` `
アンディ

複数のデータセットに対してこれを行う方法はありますか?例:{fileOne:data、fileTwo:data、fileThree:data}をAPI呼び出しから取得し、ダウンロードした3つのファイルを一度に生成しますか?ありがとう!
il0v3d0g

うーん、私はそれを試していません。ただし、いつでも画像をzipファイルに圧縮してダウンロードできます。可能か確認します。
Alain Cruz

4

これが一時的な非表示フォームを使用する私の解決策です。

//Create an hidden form
var form = $('<form>', {'method': 'POST', 'action': this.href}).hide();

//Add params
var params = { ...your params... };
$.each(params, function (k, v) {
    form.append($('<input>', {'type': 'hidden', 'name': k, 'value': v}));
});

//Make it part of the document and submit
$('body').append(form);
form.submit();

//Clean up
form.remove();

私はJQueryを大量に使用していますが、ネイティブJSでも同じことができます。


3

他の人が述べたように、POSTリクエストを介してダウンロードするフォームを作成して送信できます。ただし、これを手動で行う必要はありません。

これを正確に行うための本当に単純なライブラリの1つはjquery.redirectです。標準のjQuery.postメソッドと同様のAPIを提供します。

$.redirect(url, [values, [method, [target]]])

3

これは3年前の質問ですが、今日も同じ問題がありました。編集したソリューションを探しましたが、二重のリクエストを行う必要があるため、パフォーマンスが犠牲になる可能性があると思います。したがって、サービスを2回呼び出す必要がないことを意味する別のソリューションが必要な場合は、これが私が行った方法です。

<form id="export-csv-form" method="POST" action="/the/path/to/file">
    <input type="hidden" name="anyValueToPassTheServer" value="">
</form>

このフォームは、サービスを呼び出し、window.location()の使用を回避するためにのみ使用されます。その後、サービスを呼び出してファイルを取得するために、jqueryからフォームを送信するだけです。とてもシンプルですが、この方法でPOSTを使用してダウンロードを行うことができます。呼び出しているサービスがGETの場合、これは簡単になるかもしれませんが、それは私の場合ではありません。


1
質問はajaxを使用しているため、これはajax投稿ではありません
Nidhin David '23

これは上記の問題の単なる解決策ですが、ajax呼び出しの場合はそうではありません。
Nomi Ali、

1

私はこのFileSaver.jsを使用しました。私のcsvファイルの場合、これを(coffescriptで)行いました:

  $.ajax
    url: "url-to-server"
    data: "data-to-send"
    success: (csvData)->
      blob = new Blob([csvData], { type: 'text/csv' })
      saveAs(blob, "filename.csv")

最も複雑なケースでは、データを適切に処理する必要があると思います。内部では、FileSaver.jsはJonathan Amendの回答と同じアプローチを実装しています。


1
..しかし、通常iOSでファイルをダウンロードできますか?
Alex Marshall


1

Edgeで動作するようにJonathan Amendsの 回答を取得するために、次の変更を加えました。

var blob = typeof File === 'function'
    ? new File([this.response], filename, { type: type })
    : new Blob([this.response], { type: type });

これに

var f = typeof File+"";
var blob = f === 'function' && Modernizr.fileapi
    ? new File([this.response], filename, { type: type })
    : new Blob([this.response], { type: type });

私はむしろこれをコメントとして投稿したかったのですが、その評判は十分ではありません


0

これがさまざまなソースから集められた私のソリューションです:サーバー側の実装:

    String contentType = MediaType.APPLICATION_OCTET_STREAM_VALUE;
    // Set headers
    response.setHeader("content-disposition", "attachment; filename =" + fileName);
    response.setContentType(contentType);
    // Copy file to output stream
    ServletOutputStream servletOutputStream = response.getOutputStream();
    try (InputStream inputStream = new FileInputStream(file)) {
        IOUtils.copy(inputStream, servletOutputStream);
    } finally {
        servletOutputStream.flush();
        Utils.closeQuitely(servletOutputStream);
        fileToDownload = null;
    }

クライアント側の実装(jqueryを使用):

$.ajax({
type: 'POST',
contentType: 'application/json',
    url: <download file url>,
    data: JSON.stringify(postObject),
    error: function(XMLHttpRequest, textStatus, errorThrown) {
        alert(errorThrown);
    },
    success: function(message, textStatus, response) {
       var header = response.getResponseHeader('Content-Disposition');
       var fileName = header.split("=")[1];
       var blob = new Blob([message]);
       var link = document.createElement('a');
       link.href = window.URL.createObjectURL(blob);
       link.download = fileName;
       link.click();
    }
});   

0

ajaxでWebページをダウンロードする別のソリューションがあります。ただし、最初に処理してからダウンロードする必要があるページを指します。

最初に、ページの処理を結果のダウンロードから分離する必要があります。

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

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

       関数(データ、ステータス) 
       {
            if(status == "成功") 
            {
                / * 2)回答では、以前の計算を使用するページがダウンロードされます。たとえば、これはajax呼び出しで計算されたテーブルの結果を印刷するページである場合があります。* /
                window.location.href = DownloadPage.php + "?ID =" + 29;
            }               
       }
);

//例:CalculusPage.php

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

        $ query = "INSERT INTO ExamplePage(data1、data2)VALUES( '"。$ _ POST ["data1"]。 "'、 '"。$ _ POST ["data2"]。 "')WHERE id ="。$ ID;
        ...
    }

//例: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");

    ...

このソリューションが多くの人にとって役立つことを願っています。


0

応答が配列バッファーの場合は、Ajaxのonsuccessイベントでこれを試してください。

 if (event.data instanceof ArrayBuffer) {
          var binary = '';
          var bytes = new Uint8Array(event.data);
          for (var i = 0; i < bytes.byteLength; i++) {
              binary += String.fromCharCode(bytes[i])
          }
          $("#some_id").append("<li><img src=\"data:image/png;base64," + window.btoa(binary) + "\"/></span></li>");
          return;
      }
  • event.dataは、xhrイベントの成功関数で受け取った応答です。

0

以下は、いくつかのIDで構成されるリストに基づいて複数のファイルをダウンロードし、データベースで検索するための私のソリューションです。ファイルが決定され、ダウンロードの準備ができます-ファイルが存在する場合。Ajaxを使用して各ファイルのC#MVCアクションを呼び出しています。

そして、はい、他の人が言ったように、jQuery Ajaxでそれを行うことが可能です。私はAjaxで成功し、常に応答200を送信しています。

だから、これが鍵です:

  success: function (data, textStatus, xhr) {

そしてこれは私のコードです:

var i = 0;
var max = 0;
function DownloadMultipleFiles() {
            if ($(".dataTables_scrollBody>tr.selected").length > 0) {
                var list = [];
                showPreloader();
                $(".dataTables_scrollBody>tr.selected").each(function (e) {
                    var element = $(this);
                    var orderid = element.data("orderid");
                    var iscustom = element.data("iscustom");
                    var orderlineid = element.data("orderlineid");
                    var folderPath = "";
                    var fileName = "";

                    list.push({ orderId: orderid, isCustomOrderLine: iscustom, orderLineId: orderlineid, folderPath: folderPath, fileName: fileName });
                });
                i = 0;
                max = list.length;
                DownloadFile(list);
            }
        }

次に呼び出す:

function DownloadFile(list) {
        $.ajax({
            url: '@Url.Action("OpenFile","OrderLines")',
            type: "post",
            data: list[i],
            xhrFields: {
                responseType: 'blob'
            },
            beforeSend: function (xhr) {
                xhr.setRequestHeader("RequestVerificationToken",
                    $('input:hidden[name="__RequestVerificationToken"]').val());

            },
            success: function (data, textStatus, xhr) {
                // check for a filename
                var filename = "";
                var disposition = xhr.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, '');
                    var a = document.createElement('a');
                    var url = window.URL.createObjectURL(data);
                    a.href = url;
                    a.download = filename;
                    document.body.append(a);
                    a.click();
                    a.remove();
                    window.URL.revokeObjectURL(url);
                }
                else {
                    getErrorToastMessage("Production file for order line " + list[i].orderLineId + " does not exist");
                }
                i = i + 1;
                if (i < max) {
                    DownloadFile(list);
                }
            },
            error: function (XMLHttpRequest, textStatus, errorThrown) {

            },
            complete: function () {
                if(i===max)
                hidePreloader();
            }
        });
    }

C#MVC:

 [HttpPost]
 [ValidateAntiForgeryToken]
public IActionResult OpenFile(OrderLineSimpleModel model)
        {
            byte[] file = null;

            try
            {
                if (model != null)
                {
                    //code for getting file from api - part is missing here as not important for this example
                    file = apiHandler.Get<byte[]>(downloadApiUrl, token);

                    var contentDispositionHeader = new System.Net.Mime.ContentDisposition
                    {
                        Inline = true,
                        FileName = fileName
                    };
                    //    Response.Headers.Add("Content-Disposition", contentDispositionHeader.ToString() + "; attachment");
                    Response.Headers.Add("Content-Type", "application/pdf");
                    Response.Headers.Add("Content-Disposition", "attachment; filename=" + fileName);
                    Response.Headers.Add("Content-Transfer-Encoding", "binary");
                    Response.Headers.Add("Content-Length", file.Length.ToString());

                }
            }
            catch (Exception ex)
            {
                this.logger.LogError(ex, "Error getting pdf", null);
                return Ok();
            }

            return File(file, System.Net.Mime.MediaTypeNames.Application.Pdf);
        }

応答200を返す限り、Ajaxでの成功はそれで機能し、ファイルが実際に存在するかどうかを確認できます。この場合、以下の行はfalseであり、ユーザーにそのことを通知できます。

 if (disposition && disposition.indexOf('attachment') !== -1) {

0

@ alain-cruzのものと同様の解決策が必要でしたが、複数のダウンロードがあるnuxt / vueにありました。私はブラウザが複数のファイルのダウンロードをブロックすることを知っており、csv形式のデータのセットを返すAPIも持っています。最初にJSZipを使用する予定でしたが、IEのサポートが必要だったので、これが私の解決策です。誰かがこれを改善するのを助けることができればそれは素晴らしいことですが、今のところ私にとってはうまくいきます。

APIは次を返します:

data : {
  body: {
    fileOne: ""col1", "col2", "datarow1.1", "datarow1.2"...so on",
    fileTwo: ""col1", "col2"..."
  }
}

page.vue:

<template>
  <b-link @click.prevent="handleFileExport">Export<b-link>
</template>

export default = {
   data() {
     return {
       fileNames: ['fileOne', 'fileTwo'],
     }
   },
  computed: {
    ...mapState({
       fileOne: (state) => state.exportFile.fileOne,
       fileTwo: (state) => state.exportFile.fileTwo,
    }),
  },
  method: {
    handleExport() {
      //exportFileAction in store/exportFile needs to return promise
      this.$store.dispatch('exportFile/exportFileAction', paramsToSend)
        .then(async (response) => {
           const downloadPrep = this.fileNames.map(async (fileName) => {
           // using lodash to get computed data by the file name
           const currentData = await _.get(this, `${fileName}`);
           const currentFileName = fileName;
           return { currentData, currentFileName };
         });
         const response = await Promise.all(downloadPrep);
         return response;
       })
       .then(async (data) => {
         data.forEach(({ currentData, currentFileName }) => {
           this.forceFileDownload(currentData, currentFileName);
         });
       })
       .catch(console.error);
    },
    forceFileDownload(data, fileName) {
     const url = window.URL
         .createObjectURL(new Blob([data], { type: 'text/csv;charset=utf-8;' }));
     const link = document.createElement('a');
     link.href = url;
     link.setAttribute('download', `${fileName}.csv`);
     document.body.appendChild(link);
     link.click();
   },
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.