ブラウザ親子ウィンドウ間通信


親子ウィンドウ通信要件の背景


最近、グーグルアカウントに関連する需要が実現しています.ネット上の大部分のフロントエンドに関する実装を見ると、このようなOAuth規格の下での流れがあります.
  • サブウィンドウを開く
  • サブウィンドウで承認ページにリダイレクト
  • ユーザー権限ボタンクリック
  • ユーザー認可後の認可ページは、デフォルトまたはユーザー定義uriにリダイレクトされます.
  • 承認完了
  • 一般的に、ライセンスページがライセンスされると、サブウィンドウ(ライセンスウィンドウ)が閉じられます.ブラウザの各ウィンドウは現在のウィンドウを閉じることが禁止されており、現在のウィンドウで開いている他のウィンドウのみを閉じることができます.真実がある:
    したがって、サブウィンドウを閉じるには、親ウィンドウが必要です.親ウィンドウを閉じるには、ユーザーの承認が完了した後に親ウィンドウに自分を閉じるように通知する必要があります.これは親子間ウィンドウの通信にかかわる.
    親子ウィンドウ通信には2つのケースがあります

    親子ウィンドウの同源


    ブラウザの同源戦略がまだ分からないので、自分でGoogleにしてください.OAuthフローでは親子ウィンドウが同源になることはありません.でもここでもまとめてみます.

    親ウィンドウから子ウィンドウへの通信


    子ウィンドウは親ウィンドウによって作成されます.親ウィンドウは、子ウィンドウを開いた後に子ウィンドウへの参照を取得できます.この参照により、子ウィンドウをトリガーする方法で、子ウィンドウにメッセージを渡すことができます.
    // parent code
    let child_window_handle = null;
    $('#open-child-win-btn').on('click', () => {
        child_window_handle = window.open('target_url.html', '_blank', 'width=700, height=500, left=200');
    })

    このときサブウィンドウのハンドルがありました(handler).サブウィンドウのページには、次のような方法があります.
    // child code
    function ProcessParentMsg(msg) {
        // do something with the msg
    }

    親ウィンドウは、サブウィンドウを呼び出す対応するメソッドだけで、サブウィンドウと通信を完了できます.
    // parent code
    child_window_handle.ProcessParentMsg('msg_form_parent_window');

    子ウィンドウから親ウィンドウへの通信


    サブウィンドウはwindowオブジェクトのopenerプロパティから親ウィンドウにアクセスできます.親ウィンドウのメソッドを呼び出してアップ通信を完了します.
    // child code
    window.opener.ProcessChildMsg();
    // parent code
    function ProcessChildMsg(msg) {
        // do something with msg
    }

    親子ウィンドウが同源の場合、親ウィンドウはサブウィンドウを大きく制御できます.サブウィンドウをトリガする方法に加えて、サブウィンドウのイベントを傍受することもできますが、onbeforeunloadonresizefocusなど、親子ウィンドウが異なる場合.親ウィンドウは、サブウィンドウの下のメソッドを実行することも、ウィンドウの下のイベントをリスニングすることもできません.従来想定されていたサブウィンドウのクローズの実現形態は、親ウィンドウがサブウィンドウのハンドルを取得してサブウィンドウをリスニングするonloadonloadの後に親ウィンドウを呼び出すサブウィンドウをクローズする方法である.明らかにこれは同源の状況でしか起こらない.

    親子ウィンドウが異なる


    この場合親子窓口で通信するにはHTML 5のmessage passing機能を借りる必要があります.

    親ウィンドウから子ウィンドウへの通信


    直接例を見て、親ウィンドウでサブウィンドウにメッセージを送信
    // parent window
    let child_window_handle = window.open('child_target.html', '_blank', 'width=700, height=500');
    
    child_window_handle.postMessage('Msg to the child window', '*');

    サブウィンドウでのメッセージのリスニング
    // child window
    window.addEventListener('message', (e) => {
        ProcessParentMsg(e.data);
    });
    
    function ProcessParentMsg(msg) {
        // do something with the msg
    }

    子ウィンドウから親ウィンドウへの通信

    // child window
    window.opener.postMessage("Message to parent", "*");
    // parent window
    window.addEventListener('message', function(e) {
        ProcessChildMsg(e.data);
    }, false);
    
    function processChildMsg() {
        //  do something with the message
    }

    まとめ


    ボタンをクリックしてライセンスウィンドウを開くと、ウィンドウがブロックされているというヒントが表示され、ライセンス弾ウィンドウを直接開くことはできません.これはクリックwindow.openこの操作は非同期操作のコールバックで実行されるためである.デフォルトでは、ユーザーがこのドメイン名にポップアップウィンドウを許可するように設定しない限り、ブラウザはこの新しいウィンドウをブロックします.stackoverflowこの解釈が見られる
    The general rule is that popup blockers will engage if window.open or similar is invoked from javascript that is not invoked by direct user action. That is, you can call window.open in response to a button click without getting hit by the popup blocker, but if you put the same code in a timer event it will be blocked. Depth of call chain is also a factor - some older browsers only look at the immediate caller, newer browsers can backtrack a little to see if the caller's caller was a mouse click etc. Keep it as shallow as you can to avoid the popup blockers.
    まず、ボタンをクリックすると、ネットワークリクエストインタフェースを通じてライセンスページの接続を取得します.非同期コールバックでライセンスページリンクが取得されました.このときはwindow.openでこのリンクを開きます.これはdirect user actionではありません.遅延をもたらすため、信頼できるとしても比較的悪いユーザー体験です.そこで修正した案は,ユーザが関連ボタンをクリックしてすぐにblankウィンドウを開くことである.同時に、ライセンスページのリンクを非同期で取得します.取得後にreloadが開いたライセンスウィンドウのアドレスは、取得した接続です.これでpopup blockedという現象は起こりません.
    ここでは、ライセンスページの開発経験がない人は、サブページをどのように閉じるか理解できない可能性があります.ユーザーがライセンスページを開くと、ユーザーはライセンスボタンをクリックします.
    ページがユーザーが指定したuriにジャンプします.指定されていない場合は、そのままauthorize codeウィンドウに表示されますが、これは通常、私たちが望んでいるものではありません.この認証コードで交換する必要がありますtokentokenは本当にユーザーアカウントにログインできる一時的な証明書です.したがって、通常はユーザがuriを指定します.このuriはバックエンドインタフェースであり、認証ウィンドウがユーザに許可された後、codeのパラメータを持って私たちが提供したuriにジャンプします.このとき、バックエンドインタフェースは、認証コードを取得してtokenを交換する操作を実行することができる.その後インタフェースは1つquerystringのresponseを返し、responseが返す内容は大体以下の通りである.
    
        
        
            test
        
        
              
        
        
        window.opener.postMessage('close_child_window', '*');