• Iframe通信


     跨域的种类

    一般有两种形式的跨域问题

     ①使用XmlHttpRequest(XHR)或者使用AJAX发送的POST或者GET请求。这种形式的跨域是:前端页面与后端进行的跨域请求。

    ②父子页面之间进行的DOM操作(父子窗口之间的document操作)。这种形式的跨域是:前端页面与前端页面之间的通信或者相互操作的形成跨域。(本文主要讲这种)

    iframe通信方式:

    • 同域直接通过iframe的contentWindow 和parent去操作相应的窗口内的window.document....
    • 主域不同,设置document.domain就可以如上操作
    • 跨域及不跨均可应用:window.name、location.hash、postMessage和onmessage

    访问iframe: contentWindow
    访问父级:parent
    访问顶级:top

    1、不跨域:

    父:

    1. <body>
    2. <textarea id="message">这是高层的密码!textarea><br/>
    3. <button id="test">看看员工在说什么button><br/><br/><br/>
    4. 员工们:<br/>
    5. <iframe src="b.htm" width="500" height="300" id="iframe">iframe>
    6. <script> document.getElementById("test").onclick = function(){
    7.     alert(document.getElementById("iframe").contentWindow.document.getElementById("message").value);
    8.   }
    9. script>
    10. body>

    子:

    1. <html xmlns="http://www.w3.org/1999/xhtml">
    2. <head>
    3. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>JSONP方式title><script type="text/javascript" src="/js/jquery-1.5.1.min.js">script> head>
    4. <body>
    5. <textarea id="message">这是员工的密码!textarea><br/>
    6. <button id="test">看看领导在说什么button><br/>
    7. <script> document.getElementById("test").onclick = function(){ alert(parent.document.getElementById("message").value); } script>
    8. body>
    9. html>

    2、主域相同、子域不同

    使用document.domain=主域名

    document.domain设置规则:

    •  document.domain只设置域名或者IP地址。即:没有协议(http/https),没有端口。
    • 如果访问的地址是域名形式,则document.domain只能设置为当前域名下的同级或者父级域名,并且不能设置为顶级域名,也不可以设置为其他形式的域名(不是当前域名的父级或同级)。

    例如:当前访问地址为:https://mp.csdn.net/mp_blog/creation/editor/121540023(当前页面)。可以打开Chrome的控制台(F12)找到console的tab。默认情况下,我们输入document.domain会显示‘csdn.net’。其中csdn.net就是https://mp.csdn.net的父级域名。我们也可以设置为mp.csdn.net。因为mp.csdn.net是mp.csdn.net的同级域名。

    但是我们不能设置顶级域名,即document.domain='net',就会提示错误信息。也不能设置其他的域名形式。即document.domain='csdn1.net'或者document.domain='baidu.com'。提示也说得很清楚。必须是mp.csdn.net的一个后缀形式。

    • 如果访问地址是IP的形式,则document.domain只能设置一样的IP地址。

     注意:根据上面的设置规则,在使用document.domain的方式时,页面之间必须有相同的父级域名。否则这种方式将无法进行操作。

    a.html (http://a.xxx.com/js/crossdomain/demo/a.htm)

    1. <html xmlns="http://www.w3.org/1999/xhtml">
    2. <head>
    3. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    4. <title>Atitle>
    5. head>
    6. <body>
    7. <textarea id="message">这是高层的密码!textarea><br/>
    8. <button id="test">看看员工在说什么button><br/><br/><br/>员工们:<br/>
    9. <iframe src="http://b.xxx.com/js/crossdomain/demo/b.htm" width="500" height="300" id="iframe">iframe>
    10. <script>
    11. document.domain = "jiaju.com";
    12. document.getElementByI d("test").onclick = function(){
    13. alert(document.getElementByI d("iframe").contentWindow.document.getElementByI d("message").value);
    14. }
    15. script>
    16. body>
    17. html>

    b.html ((http://b.xxx.com/com/js/crossdomain/demo/b.htm ))

    1. <html xmlns="http://www.w3.org/1999/xhtml">
    2. <head>
    3. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    4. <title>JSONP方式</title>
    5. <script type="text/javascript" src="/js/jquery-1.5.1.min.js"></script>
    6. </head>
    7. <body>
    8. <textarea id="message">这是员工的密码!</textarea><br/>
    9. <button id="test">看看领导在说什么</button><br/>
    10. <script>
    11. document.domain = "jiaju.com";
    12. document.getElementByI d("test").onclick = function(){
    13. alert(parent.document.getElementByI d("message").value);
    14. }
    15. </script>
    16. </body>
    17. </html>

     两个域都设置:document.domain=‘jiaju.com’

    3、主域不同

    1)location.hash

    location.hash原理:
    1、动态改变location.hashiframe不会重载
    2、无论跨域与否,iframe内可以获取自己的location.hash
    3、只要域名相同就能通信,即使ABC三层嵌套

    a.html(http://www.aaa.com/demo/cross/iframe03/a.htm)嵌套了b.html(http://www.bbb.com/demo/cross/iframe03/b.html)

    1. //父页面通过hash像子页面传值
    2. var iframe = document.getElementByI d("iframe")
    3. 修改iframe.src改变其hash
    4. //子页面监听hash改变,获取hash上的值:window.location.hash
    5. //子页面=》父页面:要知道iframeid
    6. var hash_url = window.location.hash,
    7. datas = hash_url.split("#")[1].split("&"),
    8. data = {};
    9. for(var i = 0;i
    10. var t = datas[i].split("=");
    11. data[t[0]] = decodeURIComponent(t[1]);
    12. }
    13. document.domain = "jiaju.com";
    14. switch(data["JJtype"])
    15. {
    16. case "height":
    17. try{top.window.document.getElementByI d(data["iframeID"]).height = data["height"];}catch(e){}
    18. break
    19. case "width":
    20. try{top.window.document.getElementByI d(data["iframeID"]).width = data["width"];}catch(e){}
    21. break
    22. case "callback":
    23. try{top.window[data["fn"]].call(document,data);}catch(e){}
    24. break
    25. default:
    26. }

    location.hash缺点
    1、传递数据量有限
    2、不太安全

    2)window.name

    location.hash缺点
    1、传递数据量有限
    2、不太安全

    window.name

    window.name 是什么:
    name 在浏览器环境中是一个全局window对象的属性
    当在 iframe 中加载新页面时,name 的属性值依旧保持不变
    name 属性仅对相同域名的 iframe 可访问
    window.name 的优势:

    • 数据量更大(2M)
    • 更安全
    • 可传递多种数据格式

    window.name 的劣势:

    • 只适用于隐藏iframe的情形

    原理(1) :
    A创建iFrame B,把要传递的数据放入window.name

    打开Chrome的控制台,当前地址为:www.baidu.com。你在console的控制台中输入window.name='moxiao',然后将当前页面的地址栏的地址改为:mai.qq.com,然后在console的控制台中打印window.name将会显示:‘moxiao’

    跨域iframe怎么调用父页面方法

     若父页面: parent.html;嵌在父页面的子iframe页面:child.html

    1)同域时 iframe 调用父页面的JS方法

    在同域的情况下,子iframe页面可以很方便地直接调用父页面定义的JS方法:window.parent.fn(); 或者 window.top.fn();

    • window.self: 当前窗口自身的引用
    • window.parent: 上一级父窗口的引用
    • window.top: 最顶层窗口的引用

    当页面中不存在 iframe 嵌套时,则 window.self, window.parent, window.top 三者均是当前窗口自身的引用。

    2)不同域时 iframe 调用父页面的JS方法

    不同域时上面方式调用,不报跨域错误

    postMessage 的发送与接收,Window.postMessage 是 HTML5 提供的一个跨域解决方案

    1、发送:otherWindow.postMessage(message, targetOrigin, [transfer]);

    • otherWindow:其他窗口的一个引用,如iframe的contentWindow属性、执行window.open返回的窗口对象、或者是命名过或数值索引的window.frames; 
    • message: 将要发送到其他 window的数据;
    • targetOrigin: 通过窗口的origin属性来指定哪些窗口能接收到消息事件,其值可以是字符串”*”(表示无限制)或者一个URI。

    2:接收:

    1. //event.data :传递过来的信息,也就是 postMessage 中发出的 message;
    2. //event.origin: 发送信息页面的域名,包括协议和端口号。
    3. window.addEventListener("message", function(event){
    4. var data = event.data;
    5. // 判断域名
    6. if(event.origin == 'http://192.168.1.237'){
    7. //doSomething()
    8. }
    9. });
    • 父页面像子页面通信:ifram的contentWindow.postMessage
    • 子页面像父页面通信:window.parent.postMessage或window.top
    • 接收的话直接window监听onmessage事件即可

    实现:

    • a.com 域名下的父页面 parent.html 定义了功能函数 sayHi();父页面 parent.html 中嵌套了子 iframe 页面 child.html(在域名b.com域名下) 。
    • 在child.html中引起触发、执行父页面定义的 sayHi()方法。
    • 在child.html中向父页面请求获取数据 uname 值。

    1) child.html代码:

    1. <script type="text/javascript">
    2. // 1)触发父页面定义的方法
    3. window.SDK.sayHi({msg: 'hi'});
    4. // 2)向父页面请求获取数据 uname
    5. var uname = '';
    6. window.SDK.getUname();
    7. setTimeout(function(){
    8. uname = window.SDK.uname;
    9. //doSomething(uname);
    10. }, 200);
    11. // 备注:发送请求后,需要延时接收返回的数据
    12. script>

    2) child.html 中引入的js文件 sdk_child.js 代码:

    1. ;(function(){
    2. var sdk = window.SDK || {};
    3. sdk.uname = null;
    4. //发送
    5. sdk.getUname = function(){
    6. window.top.postMessage({
    7. action: "getUname"
    8. }, "*")};
    9. sdk.sayHi = function(info){
    10. window.top.postMessage({
    11. action: "sayHi",
    12. info: {
    13. msg: info.msg
    14. }
    15. }, "*")};
    16. //接收
    17. window.addEventListener("message", function(e){
    18. var res = e;
    19. var action = res.data.action;
    20. var info = res.data.info;
    21. //判断域名
    22. if(res.origin == 'a.com'){
    23. switch (action) {
    24. case 'getUname' :
    25. sdk.uname = info;
    26. break;
    27. default :
    28. return
    29. }
    30. }
    31. });
    32. //写入window
    33. window.SDK = sdk;
    34. })();

    3) parent.html 中引入的js文件 sdk_parent.js代码:

    1. ;(function(){
    2. var iframecont = document.getElementById('gameIframe').contentWindow;
    3. var sdk ={
    4. getUname: function(){
    5. var info = Tool.pareUrl(location.href);
    6. iframecont.postMessage({action: 'getUname', info: 'zhangsan'}, 'b.com');
    7. },
    8. sayHi: function(info){
    9. alert(info.msg);
    10. },
    11. };
    12. //监听接收
    13. window.addEventListener("message", function(e){
    14. var res = e;
    15. var data = e.data;
    16. var info = e.data.info;
    17. if(true){
    18. switch (data.action) {
    19. case 'sayHi' :
    20. sdk.sayHi(info);
    21. break;
    22. case 'getUname' :
    23. sdk.getUname();
    24. break;
    25. default :
    26. return
    27. }
    28. }
    29. });
    30. })();
  • 相关阅读:
    用于LLM的Chain-of-Symbol Prompting(符号链提示、CoS)
    早餐与风景
    node实现basic认证 及fs模块读取html,进行路由跳转
    最新影视视频微信小程序源码-带支付和采集功能/微信小程序影视源码PHP(更新)
    java中的异常
    时间复杂度与空间复杂度
    leetcode竞赛:20220918双周赛
    【iOS逆向与安全】某音App直播间自动发666 和 懒人自动看视频
    【Bluetooth蓝牙开发】十二、BLE协议——GATT详解
    vue_router_webpack_imported_module_0__.define is not a constru
  • 原文地址:https://blog.csdn.net/CamilleZJ/article/details/128056333