22

ため息、私たちはこれに戻っています。AWS S3バケットにファイルを直接アップロードするのに十分なブラウザで、CORSを簡単に使用できます。しかし(来ていた)、IEではIframeにフォールバックする必要があります。簡単、非表示のIframeを設定し、フォームを作成し、ターゲットをIframeの名前/ IDに設定し、フォームを送信します。アップロードが成功すると、Iframeは指定したURLにリダイレクトされ、必要なものにアクセスできます。ただし、エラーが発生した場合、IframeはAWSドメイン上にあるため、エラーのXMLコンテンツにアクセスできなくなります。実際、エラーが発生したことすらわかりません。

インターネット上の勇敢な人々が、ファイルがアップロードされるのと同じバケットでhtmlファイルをホストし、postMessagesを使用してIframeコンテンツなどをルーティングすることについて話しているのを見てきました。

誰かがこの神話上の解決策を達成する方法を私に説明してもらえますか?BlueimpによるjQueryファイルアップローダーはこれを解決しているようですが、神によってコードは非常にjQuery化されているため、その要点を理解することができませんでした。

明確にするための編集

  1. IE<10にはFileReaderAPIがありません。
  2. 1のため、XDomainRequestを使用してS3にファイルを送信できません
  3. したがって、Iframeを使用して、完全なフォームと一緒にS3に投稿してください
  4. 成功すると、AWSはサーバー上のページにリダイレクトします。サーバーはヘッダーを読み取り、
    クライアントのスクリプトで読み取ることができるJSONPスタイルの応答を返します(リダイレクトページは
    私が指定できます)。
  5. エラーが発生した場合、現時点でできることは、タイムアウトが期限切れになるのを待ってから
    、IFRAME IDをコンソールログに記録し、アラートをポップアップして、ユーザーがIDでiframeをクエリし、
    DAMNXMLコンテンツを読み取ることができるようにすることです。 AWSで指定されたエラーを取り除き、再試行します(私は皮肉です。)
4

4 に答える 4

19

jQuery File Upload プラグインが iframe アップロードを行う方法について知っておく必要があるほとんどすべては、そのIframe Transport プラグインにあります ( result.htmlページのサポートとともに)。

導入として、 Cross domain uploads wiki ページ、特にCross-site iframe transport uploadsセクションでユーザーの指示を読むことをお勧めします。(彼らのブラウザ サポートページによると、アップロードの進行状況などの機能は IE 10 未満ではサポートされていないことに注意してください。そのため、少なくとも多大な労力を費やさなければ、iframe トランスポートを使用してこれらが可能であるとは考えません。)

(また、ファイル アップロード プラグインを使用した S3 アップロードの実装では、ファイル アップロード エラーの XML コンテンツにアクセスできないと思います)

Iframe トランスポート プラグインは、jQuery 用の新しい Ajax "トランスポート" メソッドを追加します。これは、ファイル アップロード プラグインに固有のものではありません。jQuery.ajaxTransport()のドキュメントを読んで、新しいトランスポートを追加するために jQuery が提供する API を理解することをお勧めします。


Iframe Transport プラグインの機能と、Amazon S3 へのファイルのアップロードとの関係を要約してみます。

  1. ファイルのアップロードがトリガーされると、send()関数が呼び出されます。この機能:

    • 非表示のフォーム要素を作成します

    • で iframe 要素を作成し、イベント ハンドラーを iframe にsrc="javascript:false;"バインドします。load

    • 非表示フォームに iframe を追加し、非表示フォームをドキュメントに追加します。

  2. iframe が作成され、その「ページ」が読み込まれると、そのloadイベント ハンドラーが呼び出されます。ハンドラー:

    • iframe から自分自身をクリアし、別のloadイベント ハンドラーをバインドします。

    • 非表示のフォームを構成します。

      • フォームactionは S3 バケットの URL になります

      • フォームtargetは iframe に設定されているため、サーバーの応答は iframe に読み込まれます。

      • などの他のフィールドAWSAccessKeyIdが追加されます。具体的には、サーバー上のresult.htmlsuccess_action_redirectの URL に設定されます。http://example.org/result.html?%s

        通常、%sトークンはサーバー側のコードでアップロード結果に置き換える必要がありますが、S3 では、アップロードが成功した場合にのみ Amazon がこの URL にリダイレクトするため、これをコードで成功値にハードコーディングできます。

      • 元のフォームのファイル入力フィールドは非表示のフォームに移動され、複製されたフィールドは元のフィールドの場所に残されます

    • 非表示のフォームを送信します

    • ファイル入力フィールドを元のフォームに戻し、複製されたフィールドを置き換えます

  3. ファイルが S3 にアップロードされます。成功すると、Amazon は iframe をsuccess_action_redirectURL にリダイレクトします。成功しなかった場合、Amazon はエラーを返します。これも iframe に読み込まれます。

  4. iframe のloadイベント ハンドラーが呼び出されます。ハンドラー:

    • documentiframe のオブジェクトへの参照を保存しようとします。ファイルのアップロードが失敗した場合、ハンドラーはundefined代わりに を保存します。

    • document成功コードと iframe のオブジェクト (またはundefined)への参照を使用して、完全なコールバックを呼び出します。

    • 非表示のフォーム (および iframe) を削除します

  5. 制御がコードに返される前に、想定していたデータのタイプに応じて、iframe のdocumentオブジェクトが ( Iframe Transport プラグインの下部にある) コンバーターに渡されます。コンバーターはオブジェクトからそのデータを抽出し、それを (またはファイルのアップロードが失敗した場合は) コールバックにdocument返します。undefined

  6. コールバック (successおよび/またはjQuery.ajax()completeに渡されたもの) が呼び出されます。成功コードはプラグインによって常に返されるため、コールバックはトリガーされません。error

    コールバックに渡されたデータが に含めた値である場合success_action_redirect、ファイルのアップロードは成功しています。データがundefinedの場合、ファイルのアップロードは失敗しました。


更新:エラー XML ページが S3 バケットと同じオリジンにある場合、別の iframe にロードされた S3 バケットの別のページが元の iframe のコンテンツにアクセスできます (同じオリジンからのものであるため)。あなたのメインページは、postMessage()( IE6/7 をサポートする必要がある場合は easyXDM のFlashTransportを使用して) この 2 番目の iframe と通信できます。

于 2013-02-02T09:11:33.307 に答える
3

FileReader や FormData をサポートしていないブラウザーを使用しているユーザーに正確なフィードバックを提供するというこの問題は、私も非常に悩まされてきました。私は解決策を考え出すために丸3日を費やし、最終的に何もないことに近いものを思いついた.

事実に取り掛かりましょう:

  • Browser : IE8/9 // FileReader をサポートしていない他のブラウザーである可能性は低い
  • アップロード動作: UX の理由から、「Ajax」である必要があります
  • Toolbelt : jQuery ファイルのアップロード*

わかりました、iframe を使用する以外にファイルをアップロードする方法はありません。右?

したがって、@jeferry_to が説明しているように、jQuery Iframe Transport を使用した jQuery ファイルのアップロードは、この仕事のためのツールです。

*実際には、ツール/プラグインは何も変更しません..

今何?

ええと... トランスポート iframe 内の S3 レスポンスにアクセスする必要があります。しかし、別のドメインにあるため、できません。そこで、2 番目の iframe を使用するこのトリックを使用して対処することにしました。

セットアップ:

  • TopFrame、私たちのページ (www.myhost.com)
  • プラグインによって自動作成された iframe TransportFrame (s3.amazonaws.com) - S3 レスポンスが含まれます
  • iframe XDMFrame (s3.amazonaws.com) は、注文時に TransportFrame にアクセスし、応答を取得して TopFrame に配信します。

シナリオ:

まず、jQuery Iframe Transport を変更して、自動生成されたフォームとトランスポート フレームを自動的に削除しないようにする必要があります。これを行う必要があるのは、後で使用する #postMessage が本質的に非同期であり、アクセスしようとするまでに iframe が消えてしまうのを避けるためです。

  1. TopFrame では、jQuery File Upload を使用してファイルを S3 にアップロードします。アップロードされていることを確認し、それ以外の場合はエラーを取得します。
  2. TopFrame は #postMessage を使用して XDMFrame にクロス ドメイン メッセージを送信し、TransportFrame の名前を指定します。このメッセージは実際には、「iframe X の内容を確認してください」というメッセージであり、em を私に送り返す場合に表示されます。
  3. 次に XDMFrametop.frames['iframe X'].document.documentElementは、TransportFrame の内容にアクセスし、それらを文字列化し、#postMessage を介して TopFrame に送り返します。
  4. TopFrame はメッセージを受け取り、適切なフィードバックをユーザーに表示し、jQuery Iframe Transport の変更により残ったフォームと iframe を削除します。

OK、すべてが本によって行われるため、すべてが機能するはずです。

いや、気にする必要さえありません。

ほら...最新のブラウザでXHR2の代わりにiframeトランスポートを使用するように強制すると、上記のソリューションは実際に魅力的に機能します。

しかし、それは無意味です。IE8 + 9 で動作するようにしたいと考えています。

ええと... IE8/9では、うまくいくこともあれば、うまくいかないこともあります。通常はそうではありません。

なんで?IE の分かりやすい HTTP エラー メッセージのためです。ああ、あなたはよく読んでいます。

エラーが発生した場合、S3 はエラー (400、403 など) に応じて HTTP エラーステータスで応答します。現在、ここに示されているように、ステータスと応答の長さに応じて、IE は S3 応答を破棄し、わかりやすいエラー メッセージに置き換えます。これを克服するには、応答が常に > 512 バイトであることを確認する必要があります。この場合、応答を制御できないため、そのようなことを保証することはできません。S3 はそうであり、典型的なエラーは 512 バイト未満です。

要するに:

iframe トリックは、それを必要としないブラウザーでは機能しますが、必要なブラウザーでは機能しません。

残念ながら、他に何も考えられないので、そのケースは現在クローズされています。

于 2014-08-07T11:43:27.543 に答える
1

コメントで私の答えを要約すると: IE はいくつかの制限付きで CORS をサポートしています: http://www.html5rocks.com/en/tutorials/cors/

S3 への直接アップロードのこの実装は、jquery fileupload よりもはるかに単純に見えますが、jquery にはありません 。君の

お役に立てれば!

于 2013-01-29T09:36:07.700 に答える
1

「postMessage」シナリオの場合と同様に、iframe に単純な JavaScript を含める必要があります。

[編集] エラーメッセージによって引き継がれた iframe について

IFRAME スクリプト

window.document.onload = function(e){ 
    window.parent.postMessage(document, '*'); //replace '*' with your parent if possible   
}
// just to get the proper document for the parent to target me
window.addEventListener('message',function(e) {
    if (e.domain == 'example.com') { // the domain of your parent frame
        if (e.data == "Salute") {
            window.parent.postMessage("I'm here", '*'); //replace '*' with your parent too
        }
    }
});

これで、親は iFrame を完全に認識し、そのステータスを追跡できます (単純な postMessage に応答しているかどうかによって異なります)。

親スクリプト

var iFrameTarget;
var iFrameTakenOver = false;
var timer;
window.addEventListener('message',function(e) {
    if (e.domain == 'example.com') { // the domain of your iframe
        if (e.data) { // e.data contains the iframe document
            if(typeof(e.data) =='object')
                iFrameTarget = e.source;
            elseif(e.data == "I'm here")
            {
                iFrameTakenOver = false;
            }
            timer =setInterval(call_iFrame(),5000); // check iFrame presence in 5 seconds
        }
    }
});

function call_iFrame() {
    iFrameTarget.postMessage('Salute');
    iFrameTakenOver = true;
}

iframe がその「コード」で応答しない場合、iFrameTakenOver は、エラーが発生したかどうかを検証する false チェックに永続的に設定されます。

于 2013-02-07T05:15:00.513 に答える