跨文檔通訊的7種方法

摘要

如下總結的跨文檔通訊方法,均是在服務器不參與的狀況下(服務端無需特殊的代碼)實現的html

這裏的通訊,是指頁面A向頁面B傳遞信息node

大體分爲如下三類web

  • 經過 window.postMessage 實現雙向通訊
  • 經過客戶端存儲實現通訊數據庫

    • cookie
    • webStorage
    • indexedDB
  • 在頁面跳轉的過程當中攜帶信息跨域

    • window.name
    • Url 中 hash
    • window.history.replace() && document.referrer

其中第一種方法沒有跨域的限制,且實現的是雙向通訊;第二種方法本質上利用的是同源文檔能夠訪問同一塊數據實現通訊;第三種方法只能實現定向的單次的通訊,且沒有跨域的限制瀏覽器

經過 window.postMessage 實現通訊

搭建服務端

const http = require('http')
const fs = require('fs')

http.createServer((req, res) => {
  fs.readFile(`.${req.url}`, (err, data) => res.end(data))
}).listen(8888)

編寫文檔 index1.html

...
<body>
    index1
    <button id='newWindow'>new Window</button>
    <button id='sendMessage'>Send Message</button>
    <script>
        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)

    </script>
</body>
...

編寫文檔 index2.html

...
<body>
    index2
    <script>
        window.addEventListener('message', receiveMessage, false)
        function receiveMessage(event){
            console.log(event.data)
            event.source.postMessage('messageFromIndex2', event.origin)
        }
    </script>
</body>
...

以上代碼實現了經過 index1.html,新建窗口 index2.html安全

index1.html 向 index2.html 發送消息 messageFromIndex1服務器

index2.html 收到來自 index1.html 的消息,並返回消息 meesageFromIndex2cookie

index1.html 和 index2.html 互相傳遞消息的過程並不須要服務端參與post

測試過程

啓動服務器 node server.js

訪問 http://localhost:8888/index1.html

前後點擊 new Windowsend Message,能夠看到在 index1.html 和 index2.html 的控制檯中分別出現了 messageFromIndex2messageFromIndex1

補充

經過 postMessage 能夠實現跨域的信息傳遞,所以也要注意傳遞信息的過程當中要檢查信息的安全性

經過客戶端存儲手段實現通訊

將須要傳遞的信息保存在客戶端中,只有同源的文檔才能訪問,具體的實現方式有

  • cookie
  • webStorage
  • IndexedDB

經過設置 cookie 進行通訊

當服務端沒有設置 cookie 爲 HttpOnly 時,能夠在瀏覽器端設置和訪問 cookie,而 cookie 本質上是服務器發送到用戶瀏覽器並保存在瀏覽器上的一塊數據,同源的文檔能夠訪問 cookie

修改 index1.html

...
<body>
    index1
    <button id='newWindow'>new Tab</button>
    <script>
        const newWBtn = document.getElementById('newWindow')
        newWBtn.addEventListener('click', () => {
            document.cookie = 'name=test'
            window.open(`${document.origin}/index2.html`)
        })
    </script>
</body>
...

修改 index2.html

...
<body>
    index2
    <script>
        console.log(document.cookie)
    </script>
</body>
...

能夠看到在 index2.html 的控制檯中打印出了信息 'name=test'

經過 cookie 進行跨文檔通訊,就像同源文檔訪問同一個對象

經過 webStorage 進行通訊

webStorage 就像一個數據庫,同源的文檔訪問同一個子數據庫

具體操做方法以下

  • window.localStorage.setItem(key, value)
  • window.localStorage.getItem(key)

經過 indexedDB 進行通訊

indexedDB 就是一個數據庫

修改 index1.html

...
<body>
    index1
    <a href="./index2.html" target="_blank">index2.html</a>
    <button id='addBtn'>add Data</button>
    <button id='printBtn'>print Data</button>
    <script>
        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)
            }
        })
    </script>
</body>
...

修改 index2.html

...
<body>
    index2
    <button id='printBtn'>print Data</button>
    <script>
        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)
            }
        })
    </script>
</body>
...

如此實如今 index1.html 中修改 indexedDB 中存儲的數據時,index2.html 中也能夠訪問到,以此來間接實現通訊

indexedDB中文入門教程詳解

頁面跳轉的過程當中攜帶信息

如下這些方法都沒有域的限制,但對跳轉到新頁面的方式有限制

經過 window.name 進行通訊

設置 window.name = message

當經過 window.location.href 或 <a href='./index2.html'>index2.html</a> 在當前窗口載入新頁面時,window.name 仍保存着上個頁面所設置的信息

修改 index1.html

...
<body>
    index1
    <a href="./index2.html">index2.html</a>
    <script>
        window.name = 'messageFromIndex1'
    </script>
</body>
...

修改 index2.html

...
<body>
    index2
    <script>
        console.log(window.name)
    </script>
</body>
...

會在控制檯輸出 messageFromIndex1

經過在 url 中添加 hash 字段

修改目標文檔的 url,將想要傳遞的信息保存在 url 的 hash 字段中

經過 window.history.replace() 和 document.referrer

設置 window.history.replaceState(window.history,state, document.title, 'message')

從該頁面到新頁面後,經過 document.referrer 就能夠看到來自上個頁面的信息

修改 index1.html

...
<body>
    index1
    <a href="./index2.html" target="_blank">index2.html</a>
    <script>
        window.history.replaceState(window.history.state, document.title, 'messageFromIndex1')
    </script>
</body>
...

修改 index2.html

...
<body>
    index2
    <script>
        console.log(document.referrer)
    </script>
</body>
...

會在控制檯輸出 http://localhost:8888/messageFromIndex1

這裏利用的是 window.history.replaceState() 修改 url,並不會使頁面從新加載,因此將信息存在 url 中

document.referrer 會保存返回跳轉或打開到當前頁面的那個頁面的 url

相關文章
相關標籤/搜索