ドキュメント間通信の7つの方法


サマリ
以下にまとめるドキュメント間通信方法は,いずれもサーバが参加しない場合(サービス側が特別なコードを必要としない)に実現される.
ここでの通信とは、ページAがページBに情報を伝達することである
大きく分けて以下の3種類
  • windowを通ります.PostMessage双方向通信
  • を実現
  • クライアントストレージによる通信
  • cookie
  • webStorage
  • indexedDB

  • ページジャンプ中に情報を携帯
  • window.name
  • Url中hash
  • window.history.replace() && document.referrer


  • 第1の方法は、ドメイン間の制限がなく、双方向通信を実現する.第2の方法は本質的に、同じソースドキュメントが同じデータにアクセスして通信を実現することができることを利用する.第3の方法は、指向性のある単一の通信しか実現できず、ドメイン間の制限はない.
    Windowsを通ります.PostMessage通信を実現
    サービス・エンドの構築
    const http = require('http')
    const fs = require('fs')
    
    http.createServer((req, res) => {
      fs.readFile(`.${req.url}`, (err, data) => res.end(data))
    }).listen(8888)

    ドキュメントindex 1を作成します.html
    ...
    
        index1
        
        
        
            const newWBtn = document.getElementById('newWindow')
            const sendBtn = document.getElementById('sendMessage')
            let newWindow = null
            newWBtn.addEventListener('click', () => {
                newWindow = window.open(`${document.origin}/index2.html`)
            })
            sendBtn.addEventListener('click', () => {
                newWindow.postMessage('messageFromIndex1', document.origin)
            })
    
            window.addEventListener('message', e => console.log(e.data), false)
    
        
    
    ...

    文書作成index 2.html
    ...
    
        index2
        
            window.addEventListener('message', receiveMessage, false)
            function receiveMessage(event){
                console.log(event.data)
                event.source.postMessage('messageFromIndex2', event.origin)
            }
        
    
    ...

    以上のコードはindex 1を介して実現する.html,新規ウィンドウindex 2.html
    index1.html方向index 2.html送信メッセージmessageFromIndex 1
    index2.htmlはindex 1から受信.htmlのメッセージを返し、メッセージmeesageFromIndex 2を返します.
    index1.htmlとindex 2.htmlメッセージを互いに伝達するプロセスには、サービス側の参加は必要ありません.
    テストプロセス
    起動サーバnode server.jsアクセスhttp://localhost:8888/index1.html
    new Windowとsend Messageを前後してクリックするとindex 1に表示されます.htmlとindex 2.htmlのコンソールにはそれぞれmessageFromIndex 2とmessageFromIndex 1が表示されています
    補足
    postMessageではドメイン間の情報伝達が可能であるため,情報伝達の過程で情報のセキュリティをチェックすることにも注意が必要である.
    クライアントストレージ手段による通信
    転送する必要がある情報をクライアントに保存し、同源のドキュメントのみがアクセスでき、具体的な実装方法は
  • cookie
  • webStorage
  • IndexedDB

  • クッキーを設定して通信する
    サービス側がクッキーをHttpOnlyに設定していない場合、ブラウザ側でクッキーを設定してアクセスすることができ、クッキーは本質的にサーバがユーザーブラウザに送信してブラウザに保存したデータであり、同源のドキュメントはクッキーにアクセスすることができる.
    index 1を変更します.html
    ...
    
        index1
        
        
            const newWBtn = document.getElementById('newWindow')
            newWBtn.addEventListener('click', () => {
                document.cookie = 'name=test'
                window.open(`${document.origin}/index2.html`)
            })
        
    
    ...

    index 2を変更します.html
    ...
    
        index2
        
            console.log(document.cookie)
        
    
    ...

    index 2に見えます.htmlのコンソールに情報'name=test'が印刷されました
    同じソースドキュメントから同じオブジェクトにアクセスするように、クッキーを介してドキュメント間通信を行います.
    WebStorageによる通信
    WebStorageはデータベースのようなもので、同じソースのドキュメントが同じサブデータベースにアクセスします.
    具体的な操作方法は以下の通りです.
  • window.localStorage.setItem(key, value)
  • window.localStorage.getItem(key)

  • indexedDBによる通信
    indexedDBはデータベースです
    index 1を変更します.html
    ...
    
        index1
        index2.html
        
        
        
            let request = window.indexedDB.open('mydb', 2)
            let time = 1
            /*   objectStore   objectStore    db onupgradeneeded      */
            request.onupgradeneeded = e => {
                let db = e.target.result
                if (!db.objectStoreNames.contains('mystore')) {
                    let objectStore = db.createObjectStore('mystore', {
                        keyPath: 'id'
                    })
                    objectStore.createIndex('id', 'id', {
                        unique: true
                    })
                }
            }
            const addBtn = document.getElementById('addBtn')
            const printBtn = document.getElementById('printBtn')
            addBtn.addEventListener('click', () => {
                //      
                let request = window.indexedDB.open('mydb', 2)
                request.onsuccess = e => {
                    //         db
                    let db = e.target.result
                    let transaction = db.transaction(['mystore'], 'readwrite')
                    //    objectStore          
                    let objectStore = transaction.objectStore('mystore')
                    //        
                    objectStore.put({
                        id: '100002',
                        name: `time_${time++}`,
                    })
                }
            })
            printBtn.addEventListener('click', () => {
                //      
                let request = window.indexedDB.open('mydb', 2)
                request.onsuccess = e => {
                    //         db
                    let db = e.target.result
                    let transaction = db.transaction(['mystore'], 'readonly')
                    //    objectStore          
                    let objectStore = transaction.objectStore('mystore')
                    //        
                    objectStore.get('100002').onsuccess = e => console.log(e.target.result)
                }
            })
        
    
    ...

    index 2を変更します.html
    ...
    
        index2
        
        
            const printBtn = document.getElementById('printBtn')
            printBtn.addEventListener('click', () => {
                //      
                let request = window.indexedDB.open('mydb', 2)
                request.onsuccess = e => {
                    //         db
                    let db = e.target.result
                    let transaction = db.transaction(['mystore'], 'readonly')
                    //    objectStore          
                    let objectStore = transaction.objectStore('mystore')
                    //        
                    objectStore.get('100002').onsuccess = e => console.log(e.target.result)
                }
            })
        
    
    ...

    このようにindex 1で実現する.htmlでindexedDBに格納データを変更する場合、index 2.htmlにアクセスして、間接的に通信を実現することもできます.
    indexedDB中国語入門チュートリアルの詳細
    ページジャンプ中に情報を携帯
    以下の方法はドメインの制限はありませんが、新しいページにジャンプする方法には制限があります.
    Windowsを通ります.name通信
    Windowsを設定します.name = message
    Windowsを通るとlocation.hrefまたはindex2.htmlが現在のウィンドウに新しいページをロードするとき、window.nameは前のページで設定した情報を保存しています
    index 1を変更します.html
    ...
    
        index1
        index2.html
        
            window.name = 'messageFromIndex1'
        
    
    ...

    index 2を変更します.html
    ...
    
        index2
        
            console.log(window.name)
        
    
    ...

    コンソール出力messageFromIndex1urlにhashフィールドを追加する
    ターゲットドキュメントのurlを変更し、urlのhashフィールドに渡す情報を保存します.
    Windowsを通ります.history.replace()とdocument.referrer
    Windowsを設定します.history.replaceState(window.history,state, document.title, 'message')
    このページから新しいページに移動するとdocument.refererでは前のページからの情報が表示されます
    index 1を変更します.html
    ...
    
        index1
        index2.html
        
            window.history.replaceState(window.history.state, document.title, 'messageFromIndex1')
        
    
    ...

    index 2を変更します.html
    ...
    
        index2
        
            console.log(document.referrer)
        
    
    ...

    コンソール出力http://localhost:8888/messageFromIndex1ここで利用しているのはwindowです.history.replaceState()urlを変更すると、ページが再ロードされないため、urlに情報が存在します.
    document.refererは、現在のページにジャンプまたは開いたページに戻るurlを保存します.