web-dev-qa-db-ja.com

非同期のクロスドメインファイルアップロードを実行することは可能ですか?

可能です!以下をお読みください。


まず、この図を使用して、非同期ファイルアップロードを実現する方法を説明します。


ごめんなさい。ドメインの1つをシャットダウンしましたが、イメージが消えました。それは本当に素敵なイメージでした。これは、Stack OverflowがImgurを介して画像をアップロードできることを知る前でした。


ご覧のとおり、コツは、ページ自体ではなく、非表示のIFRAME要素にHTTP応答を読み込ませることです。 (これは、JavaScriptを使用してFORMを送信するときに、FORM要素のtargetプロパティを設定することによって行われます。)

これは機能します。ただし、私が直面している問題は、サーバー側のスクリプトが異なるドメインにあることです。 FORM-submitは、クロスドメインHTTPリクエストです。これで、サーバー側スクリプトでCORSが有効になり、私のWebページに、自分のページからそのスクリプトに対して作成されたHTTPリクエストの応答データを読み取る権限を付与します。ただし、これは、Ajax経由でHTTP応答を受け取った場合にのみ機能します。 ergo、JavaScript。

ただし、この場合、応答はIFRAME要素に向けられます。 XML応答がIFRAMEに到達すると、そのURLは削除スクリプトになります。 http://remote-domain.com/script.pl

残念ながら、CORSはこのケースをカバーしていません(少なくとも私は思う)-そのURLがページのURL(異なるドメイン)と一致しないため、IFRAMEのコンテンツを読み取ることができません。私はこのエラーを受け取ります:

安全でないJavaScriptが、URL hxxp://my-domain.com/outer.htmlのフレームからURL hxxp://remote-domain.com/script.plのフレームにアクセスしようとしました。ドメイン、プロトコル、ポートが一致している必要があります。

また、IFRAMEのコンテンツはXMLドキュメントであるため、postMessageなどを利用できるJavaScriptコードはIFRAME内にはありません。

だから私の質問は:IFRAMEからXMLコンテンツを取得するにはどうすればよいですか?

上記で述べたように、クロスドメインのHTTP応答を直接取得できます(CORSが有効)が、IFRAMEに読み込まれると、クロスドメインのHTTP応答を読み取ることができないようです。

そして、この質問が十分に解決できないかのように、私にこれらの解決策を除外させます:

  1. easyXDMおよびリモートドメインのエンドポイントを必要とする同様の手法

  2. xML応答の変更(SCRIPT要素を含めるため)、

  3. サーバーサイドプロキシ-ドメインにサーバープロキシがあり、プロキシとして機能する可能性があることを理解しています。

では、これらの2つのソリューションは別として、これを行うことができますか?


できます!!

multipart/form-data FORMの送信を模倣するXHR要求(Ajax要求)を偽造することが可能であることがわかります(これは上の画像でファイルをサーバーにアップロードするために使用されます)。

トリックはFormDataコンストラクターを使用することです-詳細については このMozilla Hacksの記事 をお読みください。

これがあなたのやり方です:

// STEP 1
// retrieve a reference to the file
// <input type="file"> elements have a "files" property
var file = input.files[0];

// STEP 2
// create a FormData instance, and append the file to it
var fd = new FormData();
fd.append('file', file);

// STEP 3 
// send the FormData instance with the XHR object
var xhr = new XMLHttpRequest();
xhr.open('POST', 'http://remote-domain.com/script.pl', true);
xhr.onreadystatechange = responseHandler;
xhr.send(fd);

上記のメソッドは非同期ファイルアップロードを実行します。これは、上記の画像で説明されている通常のファイルアップロードと同等であり、このフォームを送信することで実現されます。

<form action="http://remote-domain.com/script.pl" 
        enctype="multipart/form-data" method="post">
    <input type="file" name="file">
</form>

偉ぶって :)

47
Šime Vidas

フォームを送信する代わりに、フォームからのデータを含むクロスドメインXHRリクエストを送信するだけです。 CORSは前者専用です。

他の方法で行う必要がある場合は、postMessageを使用してフレームとネゴシエートします。

また、IFRAMEのコンテンツはXMLドキュメントであるため、IFRAME内にはpostMessageなどを利用できるJavaScriptコードはありません。

それはどのようにあなたを止めますか? HTMLまたはSVG名前空間の下にスクリプト要素を含めます(<script xmlns="http://www.w3.org/1999/xhtml" type="application/ecmascript" src="..."/>)XMLの任意の場所。

9
Eli Grey

あなたの言い方ではそれはできないと思います。通常、クロスドメインの問題がある場合、JSONpアプローチで解決できますが、これはGETリクエストでのみ機能します。 HTML5を使用すると、GETリクエストでバイナリを送信できる可能性がありますが、それは不確かです。

  • 解決策は、ローカルWebサーバーで要求をプロキシすることにより、リモートWebサービスをローカルで使用可能にすることです。これによりローカルウェブサーバーに追加の負荷がかかるため、実行不可能であると想像できます。ただし、ファイルが小さくて頻度が低い場合は、これで問題ありません。

  • 別の解決策は、ファイルを送信した後でサーバーのポーリングを開始することです。トークンを送信し、通常のJSONpを使用してサーバーのステータスをポーリングできます。この方法では、iframeから読み取る必要はありません。

  • リモートサーバーで実行されるiframeにページ全体を配置します。これは問題を解決するだけかもしれませんが、XML出力がいくつかのプロセスの最後のステップである場合、それは非常に現実的です。

処理サーバーが別のドメインにあるのには十分な理由があると思いますが、そうでなければ、これらすべての問題は発生しません。おそらく、再考する価値はありますか?

0
Halcyon