ページをリロードせずに、フラッシュを使用せずに、プログレスバー付きのクロスドメインUPLOADファイル

みんなにDrれます。

この投稿を読むことに決めてくれてありがとう。



よく知られているFancyUploaderファイルダウンローダーが常にではないという事実のため、タスクは次のとおりでしたが、特にプロキシを使用する場合、ファイルをロードするときにプログレスバーが表示されるシステムを開発する必要がありました...何でもいいでしょう、そのようなシステムがたくさんあります、しかし誰もが他のフラッシュダウンローダーまたは他のApiのいずれかを使用します。この場合、これはマイナスの開発結果です。



しばらく検索した後、apcモジュールhabrahabr.ru/blogs/webdev/17620に基づくシステムが見つかりました。 すべては問題ありませんが、テクノロジキャッシュが既に使用されているサーバーに追加のキャッシュモジュールを掛けることは無意味です。 その後、NGINXアップロード進行モジュール(http://wiki.nginx.org/NginxHttpUploadProgressModule)に関する情報に出会いましたが、それは本当に機能します...特にnginxがフロントエンドサーバーとしてサーバーにインストールされているためです。



しかし、最も興味深いのは先です。



通常、ファイルはサイト自体が存在する場所(同じドメイン)にダウンロードされますが、当社の場合はそうではありません。 すべての写真とビデオは単一のサーバー上にあり、サイトチャネルをアップロードしないように、すぐにアップロードすることができます。



アップロード進捗モジュールでnginxを設定し、 wiki.nginx.org / NginxHttpUploadProgressModuleの例を使用すると、ファイルのアップロードの進捗バーが機能しました。



ファイル自体を目的のサーバーに転送するには、あまり変更されていません。構成されたnginx自体は当然、h_t_t_p://STORAGE-SERVER.comにあるはずです。



< コード>

関数openProgressBar(){

/ *ランダムな進行IDを生成します* /

uuid = "";

for(i = 0; i <32; i ++){

uuid + = Math.floor(Math.random()* 16).toString(16);

}

/ * progress-idを含めるためにform-actionタグにパッチを適用します* /

document.getElementById( "upload")。action = " h_t_t_p://STORAGE-SERVER.com /upload.php?X-Progress-ID=" + uuid;



/ * 1000msごとにprogress-updaterを呼び出します* /

interval = window.setInterval(function(){fetch(uuid);}、1000);

}



フィードバックおよび転送されたボリュームの読み取りには、要求が使用されます

req = new XMLHttpRequest();

req.open("GET", "/progress", 1);







問題番号1、リクエストはh_t_t_p://STORAGE-SERVER.comにあり、サイト自体が配置されているサーバーにはない必要があります。また、ご存じのように、クロスドメインAjaxリクエストはセキュリティポリシーによって禁止されています。 解決策は非常にシンプルで、送信側にあるnginx構成ファイルの数行を使用して、現在のドメインから目的のドメインにリクエストをリダイレクトすることでした。

location ^~ /progress {

# proxy to upstream server

proxy_pass h_t_t_p://STORAGE-SERVER.com;

proxy_redirect default;

}







万歳...すべてが判明しました...問題は小さなものでした。ファイルが実際にh_t_t_pに書き込まれた場所に関する情報を取得します://STORAGE-SERVER.com、どのような名前で。 つまり h_t_t_pの処理://STORAGE-SERVER.com/upload.phpは、たとえば次の形式でレコード結果を送信する必要があります{'filepath': '/ user_upload / photo / 2/232/23456 / 23456.jpg'、 'filetype': '画像 '、'エラー ':' 0 '}。 もちろん、処理後に返されるデータの形式は、指定したものとは異なる場合があります。 示されているとおりです。



ソースコードでの実行後の結果は次のようになります

<iframe id="uploadframe" name="uploadframe" width="0" height="0" frameborder="0" border="0" src="about:blank">

<html>

<head>

</head>

<body>

{'filepath':'/user_upload/photo/2/232/23456/23456.jpg', 'filetype':'image', 'error':'0'}

</body>

</html>

</iframe>







つまり 最後のバイトの転送後、フォームのアクションは指定されたフレームで実行されます。



そして、判明したように、これは大きなセキュリティホールになるため、従来の手段でそこから抽出することは不可能です。 ドキュメント自体のある単一のドメイン空間にあるフレームからのみデータを取得できます。そうでない場合、mysite.comからotherdomain.comからプロパティを取得するためのアクセス許可が拒否されます。



科学的および非科学的な突破の方法によって、これを回避する方法のマスターが試されましたが、唯一の、そして判明したように、サイトリンクでアンカーを使用するのは非常に簡単でした。 ただし 、ブラウザ間の互換性のために、parent.location.hashではなく、parent.locationのみを使用する必要があります(それ以外の場合は、FireFoxでのみ機能します)。



このファイルの場合、ハンドラーは結果と一緒に行を形成するだけでなく、スクリプトを作成してから取得します

<iframe id="uploadframe" name="uploadframe" width="0" height="0" frameborder="0" border="0" src="about:blank">

<html>

<head>



<script>

parent.location="h_t_t_p://mysite.com/uploadfile/index.php#{'filepath':'/user_upload/photo/2/232/23456/23456.jpg', 'filetype':'image', 'error':'0'}";

</script>



</head>

<body>

</body>

</html>

</iframe>







その後、アンカーを読み取って処理します

function fetch(uuid) {

req = new XMLHttpRequest();

req.open("GET", "/progress", 1);

req.setRequestHeader("X-Progress-ID", uuid);

req.onreadystatechange = function () {

if (req.readyState == 4) {

if (req.status == 200) {

/* poor-man JSON parser */

var upload = eval(req.responseText);



document.getElementById('tp').innerHTML = upload.state;



/* change the width if the inner progress-bar */

if (upload.state == 'uploading') {

bar = document.getElementById('progressbar');

w = 400 * upload.received / upload.size;

bar.style.width = w + 'px';

}else if (upload.state == 'done') {

// , ,

//

window.clearTimeout(interval);



bar = document.getElementById('progressbar');

bar.style.width = '401px';



//************** *********************************

var result = window.location.hash;

location.hash='progress'; //

result = result.slice(1); // '#'

//

//javascript ( )

//**********************************************************************

}

/* we are done, stop the interval */

if (upload.state == 'done' || upload.state == 'error') {

window.clearTimeout(interval);

}

}

}

}

req.send(null);

}







そしてもちろん、ダウンロードファイルを選択するフォーム自体



<h2> </h2><br/>

<form id="upload" enctype="multipart/form-data"

action="/upload.php" target="uploadframe" method="post"

onsubmit="openProgressBar(); return true;">

<input type="hidden" name="MAX_FILE_SIZE" value="300000000" />

<input name="Filedata" type="file" label="fileupload" />

<input type="submit" value="" />

</form>

<iframe id="uploadframe" name="uploadframe" width="0" height="0" frameborder="0" border="0" src="about:blank"></iframe>



<div id="progress" style="width: 400px; border: 1px solid black; height:10px; display: none;">

<div id="progressbar"

style="width: 0px; background-color: black; margin-left:-1px; border: 0px solid black; height:10px;">

</div>

</div>



<div id="tp">(progress)</div>









それはすべて紳士です...最終的に、サイト上のダウンロードのステータス(ストレージサーバー上にない)でファイルをストレージサーバーに直接アップロードするための優れた、かなり普遍的なシステムであることが判明しました(特に現在のURLをプロセッサに送信する場合)。



このようなシステムの利点は、フラッシュや他のアプレットがないこと、ソリューションの汎用性、そして最も重要なこととして、サイトをロードせずにクロスドメインファイルをダウンロードすることです(ストレージに直接ダウンロードする)



欠点-IE6では動作しません。複数のファイルを同時にダウンロードする可能性はありません(FancyUploader3の場合のように)



ご清聴ありがとうございました。



All Articles