浏览器不同源的页面之间如何跨域通信
目录
- 1,需求
- 2,难点
- 3,思路
- 浏览器不同源的页面之间如何跨域通信?
- 4,实现
- 第1版
- 第2版
- 最终版
- 其他的问题
- 1,页面路径需完全一致。
- 2,事件注册问题
1,需求
现在有2个项目,页面路径不同源。
- ToC 的收银台项目
类似在PC端京东淘宝,支付最后一步的收银台页面,可以选择不同支付工具付款。
- ToB 的后台管理项目
可以对收银台项目整体做一些配置:样式,支付工具相关的等等,配置项很多。
需求
- 想要在后台管理项目中增删配置项后,能够实时预览收银台项目最终的展示效果
- 展示效果符合预期,则提交修改配置项的审批电子流
- 审批通过,上线
2,难点
因为2个项目的页面路径不同源,传递数据是个问题。
3,思路
首先,后台管理项目需要增加【预览】按钮,收银台项目需要增加【预览】页面。
-
需要后端参与。收银台项目的相关配置项,本来就是通过接口获取的。所以再增加一个预览数据的接口,在预览页面调用获取数据。
-
不需要后端参与。前端直接在2个页面之间通信。
第1种思路没有什么好说的,重点来说下第2种。
浏览器不同源的页面之间如何跨域通信?
-
通过 url 传参。最简单直接,不过传递的数据大小有限。
-
postMessage,传递的数据大小我实测可以超200MB!(不知道极限,因为没再往上测试)
简单来说,我们可以获取从当前页面A通过window.open打开的页面B的引用 targetWindowB,然后在A页面通过 targetWindowB.postMessage() 向B页面分发消息。
再介绍下 window.open
简单说明:window.open 有3个参数,我们只关注前2个
strUrl:新页面的地址strWindowName:新页面的名称,如果指定了该参数,则再次调用window.open(strUrl, strWindowName)时,不会再打开第2个新页面,而是跳转到打开的第1个页面并重新加载。(效果下面会有展示)
另外需要注意:调用window.open()方法以后,远程 URL 不会被立即载入,载入过程是异步的。
会有什么问题,看下实现过程就知道了。
4,实现
通过 vite 创建2个项目模拟,A 会向 B 发送数据。启动后的页面地址分别是:
- A页面(后台管理项目 manage)
http://localhost:5173 - B页面(收银台项目 cashier)
http://localhost:5174
第1版
A页面后台管理项目 manage
<script setup>
const cashierUrl = "http://localhost:5174";
const data = { name: "下雪天的夏风" };
let cashierWindow;function init() {cashierWindow = window.open(cashierUrl, "cashierWindow");if (cashierWindow) {cashierWindow.postMessage(data, cashierUrl);}
}
</script><template><h1>manage</h1><button @click="init">发送预览数据</button>
</template>
B页面收银台项目 cashier
<script setup>
window.addEventListener("message",function (event) {if (event.origin !== "http://localhost:5173") return;if (event.data) {console.log(event.data);}},false
);
</script><template><h1>cashier</h1>
</template>
效果:

可以看到收银台项目并没有接收到消息!
原因就是:调用window.open()方法以后,远程 URL 不会被立即载入,载入过程是异步的。
换句话说,因为B页面还没有加载完成,message 事件还没有被绑定时,A页面已经把消息发送了。
第2版
延迟发送消息。
function init() {cashierWindow = window.open(cashierUrl, "cashierWindow");setTimeout(() => {if (cashierWindow) {const data = { name: "下雪天的夏风" };cashierWindow.postMessage(data, cashierUrl);}}, 1000);
}
效果:

B页面成功收到消息!
问题来了,因为这个测试用例比较简单,所以 1s B页面就会加载完成。
可面对复杂的页面+网络问题,A页面如何知道B页面已经加载完成了(message 事件绑定了)?
答案是:此时B页面可以通过 window.opener 获取 A页面的引用,使用 postMessage 向A页面发送数据!
实现思路:
- B页面加载完成后,通过
window.opener.postMessage()向A页面发送一个约定字段。 - A页面接收到约定字段后,再向B页面发送目标数据。
最终版
A页面后台管理项目 manage
<script setup>
import { ref } from "vue";
const cashierUrl = "http://localhost:5174";
const cashierLoaded = ref(false);
let cashierWindow;function init() {cashierWindow = window.open(cashierUrl, "cashierWindow");if (cashierLoaded.value) {requestData();} else {window.addEventListener("message", receiveMessage, false);}
}function receiveMessage(event) {if (event.origin !== cashierUrl) return;cashierLoaded.value = event.data === "__done__";requestData();
}const data = { name: "下雪天的夏风" };
function requestData() {cashierWindow.postMessage(data, cashierUrl);
}
</script><template><h1>manage</h1><button @click="init">发送预览数据</button>
</template>
B页面收银台项目 cashier
<script setup>
const manageUrl = "http://localhost:5173";if (window.opener) {window.opener.postMessage("__done__", manageUrl);
}window.addEventListener("message",function (event) {if (event.origin !== manageUrl) return;if (event.data) {console.log(event.data);}},false
);
</script><template><h1>cashier</h1>
</template>
效果

其他的问题
1,页面路径需完全一致。
2个不同源页面通信时,要注意设置的 url 要完全一致才能接收到消息。例如 http://localhost:5174 和 http://localhost:5174/ 是不一样的!
2,事件注册问题
看下面的代码
function init() {cashierWindow = window.open(cashierUrl, "cashierWindow");if (cashierLoaded.value) {requestData();} else {window.addEventListener("message", receiveMessage, false);}
}function receiveMessage(event) {if (event.origin !== cashierUrl) return;cashierLoaded.value = event.data === "__done__";requestData();
}
init方法中,每次都要执行window.open吗,不能把cashierWindow保存起来调用requestData吗?
也可以这样做。但这个例子中是为了每次执行后,默认跳转到 B页面并刷新。
init方法中,每次都要注册message事件吗,万一打开的B页面加载较慢,又返回到A页面再次点击发送数据,岂不是又会再次注册事件吗?
确实会再次注册事件,不过没关系,因为注册相同的事件监听器,多余的监听器会被移除,只保留一个。参考
只保留一个的前提是:事件回调函数不能是匿名函数,否则还是会注册多个!所以把receiveMessage提取出来了。
我们来验证下最终版代码的效果:

而如果监听 message 事件这样写,
window.addEventListener("message",// function receiveMessage(event) { // 效果一样function(event) {if (event.origin !== cashierUrl) return;cashierLoaded.value = event.data === "__done__";requestData();},false);
再来看下效果:

以上。如果对你有帮助,可以点赞支持下!
相关文章:
浏览器不同源的页面之间如何跨域通信
目录 1,需求2,难点3,思路浏览器不同源的页面之间如何跨域通信? 4,实现第1版第2版最终版其他的问题1,页面路径需完全一致。2,事件注册问题 1,需求 现在有2个项目,页面路径…...
【云原生】K8S二进制搭建三:高可用配置
目录 一、部署CoreDNS二、配置高可用三、配置负载均衡四、部署 Dashboard 一、部署CoreDNS 在所有 node 节点上操作 #上传 coredns.tar 到 /opt 目录中 cd /opt docker load -i coredns.tar在 master01 节点上操作 #上传 coredns.yaml 文件到 /opt/k8s 目录中,部…...
HOT78-跳跃游戏
leetcode原题链接:跳跃游戏 题目描述 给定一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标。 示例 1: 输入:nums [2,3,1,1,4] 输…...
HDFS中的NAMENODE元数据管理(超详细)
元数据管理 元数据是什么元数据管理概述内存元数据元数据文件fsimage内存镜像文件edits log编辑日志 namenode加载元数据文件顺序 元数据管理相关目录文件元数据相关文件VERSIONseen_txid 元数据文件查看(OIV,OEV)SecondaryNameNode介绍checkpoint机制SN…...
区块链实验室(14) - 编译FISCO-BCOS
FISCO-BCOS是一种区块链平台,与Hyperledger和Ethereum有些不同,详见FISCO BCOS 区块链 编译FISCO BCOS源码的目的是修改或者新增其中功能模块,进行对比实验,验证新想法、新创意的效果。编译的步骤很简单,按技术文档一…...
for(auto iter:vec) 及 for(auto iter:vec) 的典型用法
【算法知识点】C11 标准引入了 auto 类型说明符。它通过变量的初始值或者表达式中参与运算的数据类型来推断变量的类型。 一、for(auto iter:vec) 的典型用法 #include <bits/stdc.h> using namespace std;int main(){string s;cin>>s;for(auto t:s){cout<<…...
【iosH5开发】IOS浏览器对于Vue3 Element-plus el-input中,input.value.focus无法聚焦问题
【iosH5开发】IOS浏览器对于Vue3 Element-plus el-input中,input.value.focus无法聚焦问题 此次项目遇到了两个问题,一个是在Vue3中el-input的input.value.focus()无法触发,但是在PC或者安卓均可触发。 // 解决方案 // 单纯的触发input.val…...
【2023】华为OD机试真题Java CC++ Python JS Go-题目0257-增强的strstr
题目0257-增强的strstr 题目描述 C 语言有一个库函数: char *strstr(const char *haystack, const char *needle) ,实现在字符串 haystack 中查找第一次出现字符串 needle 的位置,如果未找到则返回 null。 现要求实现一个strstr的增强函数,可以使用带可选段的字符串来模…...
Android 解析ping回复包
目标: 已知多个字符串,形如:“64 bytes from 39.156.66.18: icmp_seq1 ttl50 time29.7 ms” 获取 总Ping时间(XX:XX:XX格式),最小时间,最大时间,平均时间,丢包率,已发送个数…...
在外地ssh远程连接家里ubuntu服务器(Coplar内网穿透)
官网:https://www.cpolar.com/ 步骤: 可以先安装ssh许可(必须先完成,完成后在局域网内就可以连接自己服务器,但还是需要安装cpolar才可以外地连接服务器),参考[B站:Linux (Ubuntu) 如何开启SSH远程登录]((…...
windows创建占用特定端口程序
默认情况下,远程桌面使用的是3389端口。如果您想将远程桌面端口更改为8005,以达到模拟程序占用端口8005的情况,可以执行以下操作: 如执行以下命令,则1,2,3步相同操作可以跳过,直接往…...
【uniapp 定位获取详细位置】
在 uniapp 中获取定位信息方法,具体如下: 1. uni.getLocation 方法(都可): uni.getLocation({type: gcj02,success: function(res) {console.log(经度: res.longitude)console.log(纬度: re…...
后端进阶之路——万字总结Spring Security与数据库集成实践(五)
前言 「作者主页」:雪碧有白泡泡 「个人网站」:雪碧的个人网站 「推荐专栏」: ★java一站式服务 ★ ★前端炫酷代码分享 ★ ★ uniapp-从构建到提升★ ★ 从0到英雄,vue成神之路★ ★ 解决算法,一个专栏就够了★ ★ 架…...
mysql8查看执行sql记录历史,配置开启sql历史日志general_log
1.概要说明 mysql8默认未开启sql记录历史日志。 2.配置开启general_log 2.1.查看配置 general_log:是否开启sql日志。默认为OFFlog_output:日志输出位置: FILE:输出到文件。默认值TABLE:输出到表。mysql.general_log show v…...
git 版本控制与合并
一 git概述: - Git是一种分布式版本控制系统,用于跟踪和管理软件开发项目中的代码变更。 - 它允许多人协同工作,记录代码历史变更,并轻松管理多个项目版本。 **Git的主要特点**包括: 1. **分布式系统**:…...
【力扣】23. 合并 K 个升序链表 <链表指针、堆排序、分治>
目录 【力扣】23. 合并 K 个升序链表题解方法一:暴力,先遍历取出来值到数组中排序,再生成新链表方法二:基础堆排序(使用优先队列 PriorityQueue)方法三:基础堆排序(使用优先队列 Pri…...
微信小程序真机防盗链referer问题处理
公司使用百度云存储一些资源,然后现在要做防盗链,在CDN加入Referer白名单后发现PC是正常的,微信小程序无法正常访问资源了。然后是各种查啊,然后发现是微信小程序不支持Referer的修改,且在小程序开发工具是Referer是固…...
SpringBoot集成Redisson实现延迟队列
一、场景 1、下单未支付,超过10分钟取消订单 2、货到后7天未评价,自动好评 二、实现方案 1、使用xxl-job 定时任务按时检测,实时性不高 2、使用RabitMQ的插件rabbitmq_delayed_message_exchange插件 3、 redis的过期检测 redis.conf 中…...
思想道德与法治
1【单选题】公民的基本权利是指宪法规定的公民享有的基本的、必不可少的权利。公民的基本权利有不同的类别,公民的通信自由和通信秘密属于 A、人身自由 B、经济社会权利 C、政治权利和自由 D、教育科学文化权利 您的答案:A 参考答案:A 查…...
vue3登录页面
使用了element-plus <template><div class"login-wrapper"><!-- 背景图或者视频 --><div class"background" style"width: 100%; height: 100%; position: absolute; top: 0px; left: 0px;overflow: hidden;z-index:50;&qu…...
应用升级/灾备测试时使用guarantee 闪回点迅速回退
1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间, 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点,不需要开启数据库闪回。…...
label-studio的使用教程(导入本地路径)
文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...
基于FPGA的PID算法学习———实现PID比例控制算法
基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容:参考网站: PID算法控制 PID即:Proportional(比例)、Integral(积分&…...
安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件
在选煤厂、化工厂、钢铁厂等过程生产型企业,其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进,需提前预防假检、错检、漏检,推动智慧生产运维系统数据的流动和现场赋能应用。同时,…...
ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
深度学习习题2
1.如果增加神经网络的宽度,精确度会增加到一个特定阈值后,便开始降低。造成这一现象的可能原因是什么? A、即使增加卷积核的数量,只有少部分的核会被用作预测 B、当卷积核数量增加时,神经网络的预测能力会降低 C、当卷…...
视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)
前言: 最近在做行为检测相关的模型,用的是时空图卷积网络(STGCN),但原有kinetic-400数据集数据质量较低,需要进行细粒度的标注,同时粗略搜了下已有开源工具基本都集中于图像分割这块,…...
JS设计模式(4):观察者模式
JS设计模式(4):观察者模式 一、引入 在开发中,我们经常会遇到这样的场景:一个对象的状态变化需要自动通知其他对象,比如: 电商平台中,商品库存变化时需要通知所有订阅该商品的用户;新闻网站中࿰…...
AGain DB和倍数增益的关系
我在设置一款索尼CMOS芯片时,Again增益0db变化为6DB,画面的变化只有2倍DN的增益,比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析: 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...
day36-多路IO复用
一、基本概念 (服务器多客户端模型) 定义:单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用:应用程序通常需要处理来自多条事件流中的事件,比如我现在用的电脑,需要同时处理键盘鼠标…...
