postMessage前端跨域并前端监听

文约
• 阅读 4403
有时候会遇到傻X需求,比如前端单点登陆!遇到需求,就要去想解决办法,
这里我给大家做一个简单的前端单点登陆的解决方案,
用到的就是postMessage跨域信息传输以及onstorage的监听。
本文用到的知识点 koa架设静态资源服务、跨域、postMessage的用法
、onstorage监听storage

第一步、架设两个不同端口的服务

我们这里用koa2来搭建两个服务到不同的端口,来模拟一下真正的工作中需要出现的跨域情况。
非常的简单 主要用到 koa-static这个中间件
搭建起来也是非常容易的,如果大家想学node相关的知识 可以加我微信shouzi_1994 或者在博客下面留言你的联系方式 这里就不多说废话了 直接上代码 视频内会有详细的搭建步骤


// localhost:4000
const Koa = require('koa');
const path = require('path')
const static = require('koa-static')
const app = new Koa();

//设置静态资源的路径 
const staticPath = './static'

app.use(static(
    path.join( __dirname,  staticPath)
  ))

  
console.log("服务启动在4000端口")

app.listen(4000);


// localhost:3000
const Koa = require('koa');
const path = require('path')
const static = require('koa-static')
const app = new Koa();

//设置静态资源的路径 
const staticPath = './static'

app.use(static(
    path.join( __dirname,  staticPath)
  ))


console.log("服务启动在4000端口")

app.listen(4000);

第二步、跨域通讯postMessage

我们首先来看一下 postMessage的API

otherWindow.postMessage(message, targetOrigin, [transfer]);
otherWindow
其他窗口的一个引用,比如iframe的contentWindow属性、执行window.open返回的窗口对象、或者是命名过或数值索引的window.frames。
message
将要发送到其他 window的数据。它将会被结构化克隆算法序列化。这意味着你可以不受什么限制的将数据对象安全的传送给目标窗口而无需自己序列化。[1]
targetOrigin
通过窗口的origin属性来指定哪些窗口能接收到消息事件,其值可以是字符串""(表示无限制)或者一个URI。在发送消息的时候,如果目标窗口的协议、主机地址或端口这三者的任意一项不匹配targetOrigin提供的值,那么消息就不会被发送;只有三者完全匹配,消息才会被发送。这个机制用来控制消息可以发送到哪些窗口;例如,当用postMessage传送密码时,这个参数就显得尤为重要,必须保证它的值与这条包含密码的信息的预期接受者的origin属性完全一致,来防止密码被恶意的第三方截获。如果你明确的知道消息应该发送到哪个窗口,那么请始终提供一个有确切值的targetOrigin,而不是。不提供确切的目标将导致数据泄露到任何对数据感兴趣的恶意站点。
transfer 可选
是一串和message 同时传递的 Transferable 对象. 这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权。

怎么样是不是很容易理解,这里给大家中文化一下。
要传输的那个(父)子窗口.postMessage(传输的内容, 传输到哪个地址, [权限是否转移(一般不用)]);

提前说一下,要想跨域传输,必须是父子页面,也就是说,是通过js Open的页面,或者ifream嵌套的页面
好了 我们开始来写代码


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
        <!-- postMessage和iframe解决普通的跨域问题 -->
    我是端口3000网站的内容
    <button onclick="send()">发消息给儿子</button>
    
    <iframe style="display:none" src="http://localhost:4000" frameborder="0"></iframe>
<script>
        function send() { 
                window.frames[0].postMessage({a:"1"},"http://localhost:4000"); // 触发跨域子页面的messag事件
        }

    window.addEventListener('message', function(event) {
        console.info('儿子来信了', event);
    }, false);




</script>

</body>
</html>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
        <!-- postMessage和iframe解决普通的跨域问题 -->
    我是端口4000网站的内容
    <button onclick="send()">发消息给爸爸</button>
    
    <iframe style="display:none" src="http://localhost:4000" frameborder="0"></iframe>
<script>
       window.addEventListener("message",function(event){
           console.log("爸爸来信了:", event)
        },false)

      function send() {
        parent.postMessage({a:1}, 'http://localhost:3000'); // 
     }

</script>

</body>
</html>

写到这里我们已经实现了父子页面的跨域通讯,但是这个通讯只发生在一个窗口内啊,并没有达到我想要的效果,该怎么办呢。

监听数值变化,做出及时反应

到这里大家需要思考,什么东西是浏览器上的所有同域名网站都能看到的呢?
没错,storage,我们只需要对这个进行监听就好了。

这里我们选择监听 loacalStorage 现在我们对子页面做一下改进


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
        <!-- postMessage和iframe解决普通的跨域问题 -->
    我是端口4000网站的内容
    <button onclick="send()">发消息给爸爸</button>
    
    <iframe style="display:none" src="http://localhost:4000" frameborder="0"></iframe>
<script>
    
       window.addEventListener("message",function(event){
           console.log("爸爸来信了:", event)
           var data = JSON.stringify(event.data)
           window.localStorage.setItem("data",data)
        },false)

        window.onstorage(function(st){
            console.log(st.key,st.value)
        })
      function send() {
        parent.postMessage({a:1}, 'http://localhost:3000'); // 
     }

</script>

</body>
</html>

看,我们是不是到现在就能够针对跨域传输的内容做出响应了呢?

思考

现在我们做到了两个页面的跨域通讯,那么三个到多个的跨域通讯怎么做呢?其实一个道理啦。现在道理说给你了,写法自己去体验一下吧。

写在最后

大家有什么工作上的坎,想不通的问题,学习上的难点,都可以给我微信发信息,或者在博客评论,我都会尽力帮助大家,经典问题我会做成视频和大家分享。基础入门视频我还是会持续制作,不过我觉得教基础是真的难,还好我手里还有很多免费的入门视频,需要的也可以找我。完全免费。

点赞
收藏
评论区
推荐文章
徐小夕 徐小夕
4年前
当遇到跨域开发时, 我们如何处理好前后端配置和请求库封装(koa/axios版)
我们知道很多大型项目都或多或少的采用跨域的模式开发,以达到服务和资源的解耦和高效利用.在大前端盛行的今天更为如此,前端工程师可以通过nodejs或者Nginx轻松搭建起web服务器.这个时候我们只需要请求后端服务器的接口即可实现系统的业务功能开发.这个过程中会涉及到web页面向API服务器的跨域访问(由于受到浏览器的同源策略,但是业界已有很多解决方案,
Easter79 Easter79
3年前
springboot的跨域
https://www.cnblogs.com/520playboy/p/7306008.html1、对于前后端分离的项目来说,如果前端项目与后端项目部署在两个不同的域下,那么势必会引起跨域问题的出现。针对跨域问题,我们可能第一个想到的解决方案就是jsonp,并且以前处理跨域问题我基本也是这么处理。但是jsonp方式也同样有不足,不管是对
kenx kenx
3年前
SpringBoot 优雅配置跨域多种方式及Spring Security跨域访问配置的坑
前言最近在做项目的时候,基于前后端分离的权限管理系统,后台使用SpringSecurity作为权限控制管理,然后在前端接口访问时候涉及到跨域,但我怎么配置跨域也没有生效,这里有一个坑,在使用SpringSecurity时候单独配置,SpringBoot跨越还不行,还需要配置Security跨域才行。什么是跨域跨域是一种浏览器同源安全策略,即浏
科林-Colin 科林-Colin
4年前
Vue跨域解决方法
vue项目中,前端与后台进行数据请求或者提交的时候,如果后台没有设置跨域,前端本地调试代码的时候就会报“No'AccessControlAllowOrigin'headerispresentontherequestedresource.”这种跨域错误。要想本地正常的调试,解决的办法有三个:
徐小夕 徐小夕
4年前
《前端实战总结》之使用postMessage实现可插拔的跨域聊天机器人
由于笔者之前的项目中接触过聊天机器人的项目,主要实现机器人客服模块,以及支持跨多平台使用的目的,所以特地总结一下,希望有所收获。你将学到跨域技术常用方案介绍pos
Wesley13 Wesley13
3年前
Nginx解决跨域问题(CORS)
前言CORS(CrossOriginResourceSharing)跨域资源共享,是一种允许当前域(domain)的资源(比如html/js/webservice)被其他域(domain)的脚本请求访问的机制,通常由于同域安全策略(thesameoriginsecuritypolicy)浏览器会禁止这种跨域请求。 如:a.c
Stella981 Stella981
3年前
No 'Access
跨域说明前后端分离下,跨域已是一个老生常谈的话题,但很多小伙伴还是经常面临这样的问题,且解决方案多变多样。这里介绍一种简单直接的后端解决方案。解决跨域(服务端)/CorsConfig跨域@authorylyue@since2018年11
Wesley13 Wesley13
3年前
JAVA拦截器,JAVA返回结果跨域问题解决
遇到的问题:通过拦截器做权限控制,没有权限时返回了json值,结果前端请求时提示跨域了备注:我的前端站点和后端站点不是一个地址报错1:AccesstoXMLHttpRequestat'http://localhost:8089/appcicd/appinfo/getappinfos'fromorigi
Stella981 Stella981
3年前
Angular2+ iframe跨域调用父页面js
业务场景:列表页面添加一个导入功能,该导入功能由第三方页面提供,导入完成后需要通知主列表刷新数据。先来看看iframe跨域调用父页面的实现逻辑(以postMessage方式为例)_(postMessage介绍:https://developer.mozilla.org/zhCN/docs/Web/API/Window/pos
深入跨域 - 从初识到入门 | 京东物流技术团队
前言跨域这两个字就像一块狗皮膏药一样黏在每一个前端开发者身上,无论你在工作上或者面试中无可避免会遇到这个问题。如果在网上搜索跨域问题,会出现许许多多方案,这些方案有好有坏,但是对于阐述跨域的原理和在什么情况下需要用什么方案,缺少系统性的说明。大家在工作中可
深入跨域 - 解决方案
1前言前文《深入跨域从初识到入门》中,大家已经对同源与跨域的产生历史与重要性等有了一个初步的了解了,那么我们应该如何解决在日常开发中遇到的跨域引起的问题呢?2一览图我们将日常开发中的跨域解决方案大体分为两类:iframe跨域与API跨域:3iframe跨域