動的に生成されたファイルをユーザーがダウンロードできるページがあります。生成には長い時間がかかるため、「待機中」インジケーターを表示したいと思います。問題は、ブラウザーがファイルを受信したことを検出してインジケーターを非表示にする方法がわからないことです。
私は隠しフォームをリクエストしています。投稿サーバーに送信され、その結果を非表示の iframe にターゲットします。これにより、ブラウザ ウィンドウ全体が結果に置き換わることはありません。ダウンロードが完了したときに発生することを期待して、iframe の「load」イベントをリッスンします。
Content-Disposition: attachment
ファイルとともに「 」ヘッダーを返すと、ブラウザに「保存」ダイアログが表示されます。しかし、ブラウザは iframe で「ロード」イベントを発生させません。
私が試した方法の 1 つは、multi-part
応答を使用することです。つまり、添付されたダウンロード可能なファイルだけでなく、空の HTML ファイルも送信されます。
例えば:
Content-type: multipart/x-mixed-replace;boundary="abcde"
--abcde
Content-type: text/html
--abcde
Content-type: application/vnd.fdf
Content-Disposition: attachment; filename=foo.fdf
file-content
--abcde
これはFirefoxでは動作します。空のHTMLファイルを受け取り、「load」イベントを発生させ、ダウンロード可能なファイルの「保存」ダイアログを表示します。しかし、インターネットエクスプローラそしてサファリ; Internet Explorer は「load」イベントを発生させますが、ファイルはダウンロードされません。Safariはファイル (名前とコンテンツ タイプが間違っています) をダウンロードしますが、「load」イベントは発生しません。
別の方法としては、ファイルの作成を開始するために呼び出し、準備ができるまでサーバーをポーリングし、すでに作成されているファイルをダウンロードするという方法があります。ただし、サーバー上に一時ファイルを作成することは避けたいと思います。
どうすればいいですか?
ベストアンサー1
1つ可能な解決策クライアントで JavaScript を使用します。
クライアントアルゴリズム:
- ランダムな一意のトークンを生成します。
- ダウンロード要求を送信し、GET/POST フィールドにトークンを含めます。
- 「待機中」インジケーターを表示します。
- タイマーを開始し、1 秒ごとに「fileDownloadToken」(または任意の名前) という名前の Cookie を探します。
- クッキーが存在し、その値がトークンと一致する場合は、「待機中」インジケーターを非表示にします。
サーバーアルゴリズム:
- リクエスト内の GET/POST フィールドを探します。
- 空でない値の場合は、Cookie (例: "fileDownloadToken") を削除し、その値をトークンの値に設定します。
クライアントソースコード(JavaScript):
function getCookie( name ) {
var parts = document.cookie.split(name + "=");
if (parts.length == 2) return parts.pop().split(";").shift();
}
function expireCookie( cName ) {
document.cookie =
encodeURIComponent(cName) + "=deleted; expires=" + new Date( 0 ).toUTCString();
}
function setCursor( docStyle, buttonStyle ) {
document.getElementById( "doc" ).style.cursor = docStyle;
document.getElementById( "button-id" ).style.cursor = buttonStyle;
}
function setFormToken() {
var downloadToken = new Date().getTime();
document.getElementById( "downloadToken" ).value = downloadToken;
return downloadToken;
}
var downloadTimer;
var attempts = 30;
// Prevents double-submits by waiting for a cookie from the server.
function blockResubmit() {
var downloadToken = setFormToken();
setCursor( "wait", "wait" );
downloadTimer = window.setInterval( function() {
var token = getCookie( "downloadToken" );
if( (token == downloadToken) || (attempts == 0) ) {
unblockSubmit();
}
attempts--;
}, 1000 );
}
function unblockSubmit() {
setCursor( "auto", "pointer" );
window.clearInterval( downloadTimer );
expireCookie( "downloadToken" );
attempts = 30;
}
サーバーコードの例 (PHP):
$TOKEN = "downloadToken";
// Sets a cookie so that when the download begins the browser can
// unblock the submit button (thus helping to prevent multiple clicks).
// The false parameter allows the cookie to be exposed to JavaScript.
$this->setCookieToken( $TOKEN, $_GET[ $TOKEN ], false );
$result = $this->sendFile();
どこ:
public function setCookieToken(
$cookieName, $cookieValue, $httpOnly = true, $secure = false ) {
// See: http://stackoverflow.com/a/1459794/59087
// See: http://shiflett.org/blog/2006/mar/server-name-versus-http-host
// See: http://stackoverflow.com/a/3290474/59087
setcookie(
$cookieName,
$cookieValue,
2147483647, // expires January 1, 2038
"/", // your path
$_SERVER["HTTP_HOST"], // your domain
$secure, // Use true over HTTPS
$httpOnly // Set true for $AUTH_COOKIE_NAME
);
}