浏览器不同源的页面之间如何跨域通信

这篇具有很好参考价值的文章主要介绍了浏览器不同源的页面之间如何跨域通信。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1,需求

现在有2个项目,页面路径不同源。

  • ToC 的收银台项目

类似在PC端京东淘宝,支付最后一步的收银台页面,可以选择不同支付工具付款。

  • ToB 的后台管理项目

可以对收银台项目整体做一些配置:样式,支付工具相关的等等,配置项很多。

需求

  1. 想要在后台管理项目中增删配置项后,能够实时预览收银台项目最终的展示效果
  2. 展示效果符合预期,则提交修改配置项的审批电子流
  3. 审批通过,上线

2,难点

因为2个项目的页面路径不同源,传递数据是个问题。

3,思路

首先,后台管理项目需要增加【预览】按钮,收银台项目需要增加【预览】页面。

  1. 需要后端参与。收银台项目的相关配置项,本来就是通过接口获取的。所以再增加一个预览数据的接口,在预览页面调用获取数据。

  2. 不需要后端参与。前端直接在2个页面之间通信。

第1种思路没有什么好说的,重点来说下第2种。

浏览器不同源的页面之间如何跨域通信?

  1. 通过 url 传参。最简单直接,不过传递的数据大小有限。

  2. postMessage,传递的数据大小我实测可以超200MB!(不知道极限,因为没再往上测试)

简单来说,我们可以获取从当前页面A通过window.open打开的页面B的引用 targetWindowB,然后在A页面通过 targetWindowB.postMessage() 向B页面分发消息。

再介绍下 window.open

简单说明:window.open 有3个参数,我们只关注前2个

  1. strUrl:新页面的地址
  2. strWindowName:新页面的名称,如果指定了该参数,则再次调用 window.open(strUrl, strWindowName) 时,不会再打开第2个新页面,而是跳转到打开的第1个页面并重新加载。(效果下面会有展示)

另外需要注意:调用window.open()方法以后,远程 URL 不会被立即载入,载入过程是异步的
会有什么问题,看下实现过程就知道了。

4,实现

通过 vite 创建2个项目模拟,A 会向 B 发送数据。启动后的页面地址分别是:

  1. A页面(后台管理项目 manage)http://localhost:5173
  2. 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>

效果:

浏览器不同源的页面之间如何跨域通信,问题解决,web,前端,javascript,http,https

可以看到收银台项目并没有接收到消息!

原因就是:调用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);
}

效果:

浏览器不同源的页面之间如何跨域通信,问题解决,web,前端,javascript,http,https

B页面成功收到消息!

问题来了,因为这个测试用例比较简单,所以 1s B页面就会加载完成。
可面对复杂的页面+网络问题,A页面如何知道B页面已经加载完成了message 事件绑定了)?

答案是:此时B页面可以通过 window.opener 获取 A页面的引用,使用 postMessage 向A页面发送数据!

实现思路:

  1. B页面加载完成后,通过window.opener.postMessage() 向A页面发送一个约定字段。
  2. 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>

效果

浏览器不同源的页面之间如何跨域通信,问题解决,web,前端,javascript,http,https

其他的问题

1,页面路径需完全一致。

2个不同源页面通信时,要注意设置的 url 要完全一致才能接收到消息。例如 http://localhost:5174http://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();
}
  1. init 方法中,每次都要执行window.open 吗,不能把 cashierWindow 保存起来调用requestData 吗?

也可以这样做。但这个例子中是为了每次执行后,默认跳转到 B页面并刷新。

  1. init 方法中,每次都要注册message 事件吗,万一打开的B页面加载较慢,又返回到A页面再次点击发送数据,岂不是又会再次注册事件吗?

确实会再次注册事件,不过没关系,因为注册相同的事件监听器,多余的监听器会被移除,只保留一个。参考
只保留一个的前提是:事件回调函数不能是匿名函数,否则还是会注册多个!所以把 receiveMessage 提取出来了。

我们来验证下最终版代码的效果:

浏览器不同源的页面之间如何跨域通信,问题解决,web,前端,javascript,http,https

而如果监听 message 事件这样写,

window.addEventListener(
    "message",
    // function receiveMessage(event) { // 效果一样
    function(event) {
      if (event.origin !== cashierUrl) return;
      cashierLoaded.value = event.data === "__done__";
      requestData();
    },
    false
  );

再来看下效果:

浏览器不同源的页面之间如何跨域通信,问题解决,web,前端,javascript,http,https


以上。如果对你有帮助,可以点赞支持下!文章来源地址https://www.toymoban.com/news/detail-628339.html

到了这里,关于浏览器不同源的页面之间如何跨域通信的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Python flask跨域支持(Access-Control-Allow-Origin(CORS)跨域资源共享(访问控制允许来源:允许指定的来源进行跨域请求)浏览器同源策略、OPTIONS预检请求

    浏览器的同源策略(Same-Origin Policy)限制了跨域请求,如果不进行特殊处理,跨域请求将被浏览器拦截。 接口支持跨域能够允许浏览器跨域请求不被浏览器拦截。 下面是跨域请求的一些影响、优点和缺点: 优点 允许不同域名下的应用程序进行数据交互,提高了系统的灵活性

    2024年02月11日
    浏览(34)
  • python模块websockets,浏览器与服务器之间的双向通信

    一、简介 WebSocket是一种在Web浏览器和服务器之间进行实时双向通信的协议。它通过建立一条持久的连接,允许服务器主动向客户端推送数据,实现实时性和双向通信的能力。 与传统的HTTP请求-响应模式不同,WebSocket提供了一个长时间运行的连接,可以在客户端和服务器之间进

    2024年02月21日
    浏览(37)
  • Flutter如何支持浏览器跨域

    当使用 flutter 构建 web 项目,直接运行在 chrome 浏览器发出网络请求会发生跨域错误  strict-origin-when-cross-origin(CROS) ,比如在 dart 代码直接用  dio.get(\\\"https://www.yunfuit.com\\\") ,dio 会报错,在 chrome 的 DevTools 中会发现 CROS 错误。 解决办法: 在 flutterbincache 删除 flutter_tools.stamp

    2024年02月17日
    浏览(32)
  • 浏览器同源策略

    同源策略 :是一个重要的 浏览器的安全策略 ,用于 限制一个源 的文档或者它加载的脚本如何能 与另一个源的资源进行交互 它能帮助阻隔恶意文档,减少可能被攻击的媒介 例如:被钓鱼网站收集信息,使用ajax发起恶意请求,传递转账信息给银行服务器 源 web内部的源 由

    2024年02月14日
    浏览(35)
  • 浏览器安全之同源策略

    原文合集地址如下,有需要的朋友可以关注 本文地址 合集地址 浏览器的同源策略是一种安全机制,用于保护用户信息和防止恶意代码的执行。它是由浏览器实施的一组规则,限制了不同源(origin)的网页之间的交互。 同源是指两个网页具有相同的协议(protocol),主机(

    2024年02月11日
    浏览(40)
  • 浏览器安全-同源策略和CORS

    同源策略是浏览器的一个安全功能,浏览器禁止在当前域读写其他域的资源,如限制跨域发送ajax请求 不受同源策略限制的 1)页面中的链接,重定向表单以及表单提交 2)跨域资源引入 如script不受跨域限制,可以跨域请求src 如何解决跨域访问资源 1)利用script的跨域特性绕过

    2024年02月09日
    浏览(38)
  • Selenium如何隐藏浏览器页面?

    Selenium 隐藏 浏览器 页面   背景 在工作,学习中,我们常常会使用selenium来获取网页上的数据,编完完整程序之后,实现真正意义上的自动化获取,此时我们会发现在运行中往往会弹出浏览器页面,在调试过程中,这很方便,但是跑自动化时,我们就需要将浏览器隐藏在后台

    2024年02月03日
    浏览(37)
  • 本地前端代理连接服务器后端gateway api浏览器提示cors跨域,如何解决?

    🏆本文收录于「Bug调优」专栏,主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家 关注收藏订阅 !持续更新中,up!up!up!!   本地前端代理连接服务器后端gateway api浏览器提示

    2024年04月12日
    浏览(45)
  • 在uniapp Vue3版本中如何解决web/H5网页浏览器跨域的问题

    uniapp项目在浏览器运行,有可能调用某些接口会出现跨域问题,报错如下图所示: 存在跨域问题的原因是因为浏览器的同源策略,也就是说前端无法直接发起跨域请求。同源策略是一个基础的安全策略,但是这也会给uniapp/Vue开发者在部署时带来一定的麻烦。一般来说,浏览

    2024年01月21日
    浏览(40)
  • Django项目页面样式如何“传给”客户端浏览器

    django项目在视图函数中借助 render 函数可以返回HTML页面,但是HTML页面中如果引入了外部CSS文件或者JavaScript文件在浏览器页面无法加载,因此就必须有一种方式能够将HTML文档中引入的外部文件能够在客户端浏览器上加载,这种方式就是配置静态文件。 静态文件就是前端已经写

    2024年02月02日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包