跨文档通讯的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

相关文章
相关标签/搜索