postMessage及webSocket跨域方案详解

 更新时间:2022年10月11日 10:58:56   作者:mouche  
这篇文章主要为大家介绍了postMessage及webSocket跨域方案详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

一、postMessage

我们在上一篇小白也能搞懂的JSONP和CORS跨域方案已经说过两种跨域方案了,这一篇就再继续讲讲postMessagewebsocket这两种方案,它们也能算得上是跨域方案🤓

✍是什么

  • window.postMessage() 方法提供了一种受控机制来规避此限制,只要正确的使用,这种方法就很安全
  • 听听MDN的解释:一个窗口可以获得对另一个窗口的引用,然后在窗口上调用 targetWindow.postMessage() 方法分发一个 MessageEvent 消息。接收消息的窗口可以根据需要自由处理此事件

✍语法

targetWindow.postMessage(message, targetOrigin, [transfer]);
  • targetWindow: 其他窗口的一个引用,比如 iframecontentWindow 属性、执行window.open返回的窗口对象、或者是命名过或数值索引的window.frames (en-US)
  • message: 将要发送到其他 window 的数据。它将会被结构化克隆算法 (en-US)序列化。这意味着你可以不受什么限制的将数据对象安全的传送给目标窗口而无需自己序列化
  • targetOrigin: 通过窗口的 origin 属性来指定哪些窗口能接收到消息事件,其值可以是字符串*(表示无限制)或者一个 URI。在发送消息的时候,如果目标窗口的协议、主机地址或端口这三者的任意一项不匹配它提供的值,那么消息就不会被发送;只有三者完全匹配,消息才会被发送。这个机制用来控制消息可以发送到哪些窗口
  • transfer 可选: 是一串和 message 同时传递的 Transferable 对象。这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权。

通过以上叙述我们能够了解到它的作用就是可以安全地给目标窗口发送自定义的信息

✍怎么用

有信息的发送,自然也要有信息的接收,我们可以采用addEventLister,监听message事件: 该事件接收到消息时触发

  • 我们先在同一个窗口对其进行测试(在Origin值为http://127.0.0.1:5500/的页面打开)
const data = {
  name : '某车',
  like:  '前端'
}
//传入的message为data,targetOrigin为http://127.0.0.1:5500/
window.postMessage(data, 'http://127.0.0.1:5500/');
window.addEventListener('message',(event)=>{
//监听该回调事件并打印
  console.log(event);
})
  • 我们看一下打印台,可以看到里面的data正是我们传入的数据,origin是发送消息的源,source为发送消息的窗口引用(后面这两个,用于我们回发消息,实现消息互通)

✍如何跨域

上述我们提到了其他窗口的引用可以是iframecontentWindow属性,也可以是window.open的返回值那么我们就都来试试看

iframe + postMessage

  • 这里是使用3300端口父页面向内嵌子页面3301端口发送消息
//a.html
 <!-- 使用iframe,src指向3301端口 -->
<iframe src="http://127.0.0.1:3301/b.html" id="frame" onload="load()"></iframe>
<script>
const data = {
  name : '某车',
  like:  '前端'
}
const load = function(){
  //负责发布消息
  let frame = document.getElementById('frame'); 
  const targetWindow = frame.contentWindow;//得到目标窗口的引用
  targetWindow.postMessage(data, 'http://127.0.0.1:3301'); //发送新消息
  //也监听信息
  window.onmessage = function(event) {
    console.log(event.data)
  }
}
</script>
  • 这里记得在onload事件里面去触发,否则会报如下错误

  • 3301端口监听message事件,然后通过event.source得到3300端口页面的引用,event.origin获取3300端口的源,然后可以回发消息
    //b.html
    window.addEventListener('message',(event)=>{
      console.log(event.data);
      event.source.postMessage('我可以回发消息给你', event.origin);
    })

3300端口页面的打印 (图片端口号打错了,懒得修改了..)

window.open()+postMessage

先认知一下window.open()语法

window.open(url, [name], [configuration])
  • url:为要新打开页面的url
  • name:为新打开窗口的名字,可以通过此名字获取该窗口对象
  • configuration:为新打开窗口的一些配置项,比如是否有菜单栏、滚动条、长高等等信息

还是上面的思路,我们让3300端口3301端口发送信息

   //a.html
  <button class="openWindow">打开窗口</button>
  <script>
    const btn = document.querySelector('.openWindow');
    const data = {
      name : '某车',
      like:  '前端'
    }
    //点击之后,执行window.open()
    btn.addEventListener('click', ()=>{
     const targetWindow =  window.open('http://127.0.0.1:3301/b.html', '3001端口'); //拿到目标窗口的引用
     setTimeout(()=>{
      targetWindow.postMessage(data, 'http://127.0.0.1:3301/'); //发送数据
     },1000)
    })
    //同时监听message事件
    window.addEventListener('message',(event)=>{
      console.log(event.data);
    })
  </script>
  • 3301端口监听message事件,并且回发信息
    //b.html
    window.addEventListener('message',(event)=>{
      console.log(event.data);
      event.source.postMessage('我可以回发消息给你', event.origin);
    })
  • 看一下控制台结果

3301端口打印如下

3300端口打印如下

✍兼容性

还是在IE有兼容问题

小结:postMessage()方法允许来自不同源的脚本进行有限的通信,只要能获取到源和窗口对象就可以实现跨域消息传递

二、webSocket

  • webSocket是一种在单个TCP连接上进行全双工通信的协议,它实现了浏览器与服务器全双工通信,能更好的节省服务器资源和带宽并达到实时通讯的目的
  • WebSocketHTTP都是应用层协议,都基于 TCP 协议
  • 只需要一次握手(使用HTTP协议)客户端和服务端就可以建立持久性的链接,进行双向数据传输

✍出现的原因

  • 需要实现“聊天室”,“消息推送”,“实时动态”等功能
  • 曾经的方案:
    • 短轮询;每隔一段时间就询问一次服务器是否有新的消息,缺点就是有一定的延迟,浪费资源
    • 长轮询:客户端发送请求后如果数据没有更新的话服务器就先将其挂起,有新消息则传回,等传回后又重新发起请求等待数据更新,缺点就是服务器需要保持大量的连接

✍连接流程

  • 客户端先用Upgrade:Websocket请求头的HTTP请求,向服务器发起握手请求
Connnection:Upgrade  //表示要升级协议
Upgrade: websocket //表示要升级为websocket协议
Sec-webSocket-Version:13 //版本
  • 握手成功后,即升级协议,两端就可以相互传递消息了

✍兼容性

为什么说它是解决跨域的方案:因为它本身就不受同源策略的限制,客户端可以和任意服务器之间进行通信

跨域小结

  • JSONP因为仅支持get请求,淘汰无人问津是迟早的事情
  • CORS支持所有类型的HTTP请求,是跨域HTTP请求的根本解决方案,但是我们上一篇也提了,还是有IE兼容问题
  • postMessage方法允许来自不同源的脚本进行有限的通信,只要能获取到源和窗口对象就可以实现跨域消息传递
  • websocket本身不受同源策略的限制,可以在不同源间进行通信
  • 最后还有nginx反向代理,它可以说基本没啥毛病?不过我不怎么了解它就不介绍啦🤡

以上就是postMessage及webSocket跨域方案详解的详细内容,更多关于postMessage webSocket跨域的资料请关注脚本之家其它相关文章!

相关文章

  • 浅谈typescript中keyof与typeof操作符用法

    浅谈typescript中keyof与typeof操作符用法

    本文主要介绍了typescript中keyof与typeof操作符用法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-06-06
  • Javascript必知必会(四)js类型转换

    Javascript必知必会(四)js类型转换

    这篇文章主要介绍了Javascript必知必会(四)js类型转换 的相关资料,非常不错具有参考借鉴价值,需要的朋友可以参考下
    2016-06-06
  • 使用JavaScript实现弹出层效果的简单实例

    使用JavaScript实现弹出层效果的简单实例

    下面小编就为大家带来一篇使用JavaScript实现弹出层效果的简单实例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-05-05
  • javascript下对于事件、事件流、事件触发的顺序随便说说

    javascript下对于事件、事件流、事件触发的顺序随便说说

    向同一个标签 动态的添加事件是 执行的顺序在ie和其他非ie内核的浏览器有所不同 ie是“先进先出 ” 就是最先添加的最先执行,其他非ie内核的浏览器是 “先进后出”,就是 最后添加的事件 先执行。
    2010-07-07
  • 一文详解javascript语言中的类(class)

    一文详解javascript语言中的类(class)

    class类是一种抽象的体现,用来表示具有相同特性的一类事物,是面向对象编程不可缺少的工具,下面这篇文章主要介绍了javascript语言中类class的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2025-04-04
  • zTree插件之多选下拉菜单实例代码

    zTree插件之多选下拉菜单实例代码

    zTree插件之多选下拉菜单实例代码。需要的朋友可以过来参考下,希望对大家有所帮助
    2013-11-11
  • 对Web开发中前端框架与前端类库的一些思考

    对Web开发中前端框架与前端类库的一些思考

    这篇文章主要介绍了对Web开发中前端框架与前端类库的一些思考,本文讲解了前端框架的理解误区、前端框架与前端类库的区别、前端MVC框架思想等内容,需要的朋友可以参考下
    2015-03-03
  • js函数获取html中className所在的内容并去除标签

    js函数获取html中className所在的内容并去除标签

    本文为大家介绍下如何使用js函数获取html中className所在的内容,具体实现思路如下,喜欢的朋友可以参考下
    2013-09-09
  • js实现的常用的左侧导航效果

    js实现的常用的左侧导航效果

    使用js简单实现下常用的左侧导航效果为提高导航性能而生,各位朋友可以参考应用,希望对大家有所帮助
    2013-10-10
  • javascript里模拟sleep(两种实现方式)

    javascript里模拟sleep(两种实现方式)

    有几种方式,但都不完美 其一:不断循环,直到达到指定时间、其二:用xhr同步请求后台程序,比如传2000过去,后台就sleep 2秒后再返回,这种方式也有缺点,当N多客户端都请求后台时,一直保持连接http开销很大,感兴趣的朋友可以了解下啊
    2013-01-01

最新评论