iframe跨域解决办法

本文深入解析了同源策略下,不同情境的跨域通信方法,包括不跨域时的iframe与父窗口通信,主域相同子域不同的document.domain设置,以及主域不同情况下的location.hash与window.name通信技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

按情境分
1、不跨域时
2、主域相同、子域不同时
3、主域不同

不跨域时

访问iframecontentWindow
访问父级:parent
访问顶级:top

a.html

<html xmlns="http://www.w3.org/1999/xhtml"> 
<head> 
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
    <title>A</title> 
</head> 
<body> 
    <textarea id="message">这是高层的密码!</textarea><br/> 
    <button id="test">看看员工在说什么</button><br/><br/><br/>
    员工们:<br/> 
    <iframe src="b.htm" width="500" height="300" id="iframe"></iframe> 
    <script> document.getElementById("test").onclick = function(){ 
    alert(document.getElementById("iframe").contentWindow.document.getElementById("message").value); 
  }
    </script> 
</body> 
</html>

b.html

<html xmlns="http://www.w3.org/1999/xhtml">
<head> 
    <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>
<body> 
    <textarea id="message">这是员工的密码!</textarea><br/>
    <button id="test">看看领导在说什么</button><br/> 
    <script> document.getElementById("test").onclick = function(){ alert(parent.document.getElementById("message").value); } </script>
</body>
</html>

跨域时

1、主域相同、子域不同
使用document.domain=主域名

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

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>A</title>
</head>
<body>
<textarea id="message">这是高层的密码!</textarea><br/>
<button id="test">看看员工在说什么</button><br/><br/><br/>员工们:<br/>
<iframe src="http://b.xxx.com/js/crossdomain/demo/b.htm" width="500" height="300" id="iframe"></iframe>
<script>
    document.domain = "jiaju.com";

   document.getElementByI d("test").onclick = function(){
        alert(document.getElementByI d("iframe").contentWindow.document.getElementByI d("message").value);
    }
</script>
</body>
</html>

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

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<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>
<body>
<textarea id="message">这是员工的密码!</textarea><br/>
<button id="test">看看领导在说什么</button><br/>
<script>
    document.domain = "jiaju.com";
    document.getElementByI d("test").onclick = function(){
        alert(parent.document.getElementByI d("message").value);
    }
</script>
</body>
</html>

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

2、主域不同

解决办法:
1、location.hash
2、window.name

location.hash

location.hash 是什么:
hash 属性是一个可读可写的字符串,该字符串是 URL 的锚部分(从 # 号开始的部分)

http://www.xxx.com/js/crossdomain/proxy.html#iframeID=google&height=362&JJtype=height
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>jiaju.com iframe proxy</title>
</head>
<body>
<script>
var hash_url = window.location.hash,
      datas = hash_url.split("#")[1].split("&"),
      data = {};

for(var i = 0;i<datas.length;i++){
    var t = datas[i].split("=");
    data[t[0]] = decodeURIComponent(t[1]);
}
document.domain = "jiaju.com";
switch(data["JJtype"])
    {
        case "height":
            try{top.window.document.getElementByI d(data["iframeID"]).height = data["height"];}catch(e){}
            break
        case "width":
            try{top.window.document.getElementByI d(data["iframeID"]).width = data["width"];}catch(e){}
            break
        case "callback":
            try{top.window[data["fn"]].call(document,data);}catch(e){}
            break
        default:
    }
</script>
</body>
</html>

例子
location.hash(A操作B)
A通过location.hash方式传递参数给B,B通过定时器检测hash变化,执行对应操作。
a.html(http://www.aaa.com/demo/cross/iframe03/a.htm)

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>A</title>
</head>
<body>
<textarea id="message">这是高层的密码!</textarea><br/>
<button id="test">看看员工在说什么</button><br/><br/><br/>员工们:<br/>
<iframe src="http://www.bbb.com/demo/cross/iframe03/b.htm#message=111" width="500" height="300" id="iframe"></iframe>
<script>
    var iframe = document.getElementByI d("iframe")
    document.getElementByI d("test").onclick = function(){
        var url = iframe.src,
        time = (new Date()).getTime();
        if(url.indexOf("message") != -1){
           iframe.src = url.replace(/message=\w+/,"message="+time);
        }else {
            iframe.src = url+"/#message="+time;
        }
    }
</script>
</body>
</html>

b.html

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>JSONP方式</title>
<script src="/js/crossdomain/crossdomain.js"></script>
</head>
<body>
<textarea id="message">这是员工的密码!</textarea><br/>
<button id="test">看看领导在说什么</button><br/>
<script>
var data = {};
var hash_url;
function dealHash(){
    hash_url = window.location.hash;
     var  datas = hash_url.split("#")[1].split("&");
    for(var i = 0;i<datas.length;i++){
        var t = datas[i].split("=");
        data[t[0]] = decodeURIComponent(t[1]);
    }
}
function change(){
    if(hash_url!=window.location.hash){
        dealHash();
        document.getElementByI d("message").value = data["message"];
    }
}
setInterval(change,100);
</script>
</body>
</html>

location.hash(B操作A)
A创建和上层同域的iframe通过location.hash方式传递参数给B ,B通过top.window获取顶层window对象A
a.html(http://www.aaa.com/demo/cross/iframe03/a.htm)

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>A</title>
<script>
    document.domain = "jiaju.com";
    function test(obj){
       alert(obj['message']);
    }
</script>
</head>
<body>
这里是A(第一层)<br/>
<iframe id="google" src="http://www.bbb.com/demo/crossiframe/b.html" width="1000" height="300" border=1></iframe>
</body>
</html>

b.html(http://www.bbb.com/demo/crossiframe/b.html)

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>B</title>
</head>
<body style="
<script src="/js/crossdomain/crossdomain.js"></script>
这里是B(第二层)iframe<br/>
<div id="div" style="height:200px;color:#fff;">这里高度可以变化</div>
<button id="btn">点击改变高度</button><button id="btn2">点击调用顶层callback</button>
<script>
document.getElementByI d("btn").onclick = function(){
    var div = document.getElementByI d("div");
    div.style.height = (parseInt(div.style.height)+100)+"px";
    JJcrossiframe.setHeight("google");
}

document.getElementByI d("btn2").onclick = function(){
    JJcrossiframe.callback("test",{
        message:"来自跨域的iframe的问候!"
    });
}
</script>
</body>
</html>

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

<script src="/js/crossdomain/crossdomain.js"></script>

提供以下方法:

JJcrossiframe.setHeight(‘youiframeID’) //自动设定跨域iframe高度
JJcrossiframe.setWidth(‘youiframeID’)  //自动设定跨域iframe宽度
JJcrossiframe.callback(‘fn’,paramobj)  //调用顶层iframe中fn函数
JJcrossiframe.init(paramobj , type)             //自定义向顶层传参数
//  (type目前有:height,width,callback),
//  新增type需在代理页面内自定义开发

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

### Vue 中 iframe 解决方案 在 Vue 页面中嵌套 URL 使用 iframe 时,可能会遇到问题。以下是几种常见的解决方法: #### 方法一:`document.domain + iframe` 方案 如果两个页面属于同一个顶级名,则可以通过设置 `document.domain` 来实现通信[^2]。 需要注意的是,这种方法仅适用于子名之间的情况(如 a.example.com 和 b.example.com)。通过将两者的 `document.domain` 设置为相同的值(如 example.com),可以解除部分限制。 ```javascript // 在父页面和 iframe 子页面中均需执行以下代码 document.domain = 'example.com'; ``` 此方案的优点是可以简单快速地解决问题,但存在一定的安全隐患,尤其是在多 iframe 场景下需要统一管理 domain 值。 --- #### 方法二:`postMessage` 实现通信 `window.postMessage()` 是一种安全的窗口消息传递机制,允许不同源之间进行数据交换[^1]。 父页面发送消息给 iframe: ```javascript const iframeWindow = document.getElementById('myIframe').contentWindow; iframeWindow.postMessage({ data: 'hello from parent' }, '*'); ``` iframe 接收并响应消息: ```javascript window.addEventListener('message', function(event) { console.log('Received message:', event.data); }); ``` 这种方式的优势在于它不依赖于同源策略,能够灵活处理各种复杂的场景。 --- #### 方法三:Nginx 反向代理 当无法修改 iframe 内部逻辑或者希望彻底屏蔽风险时,可以选择 Nginx 配置反向代理来伪装目标接口地址为同一名下的路径[^3]。例如,在 Nginx 配置文件中添加如下规则: ```nginx location /api/ { proxy_pass http://target-domain.com/; } ``` 这样就可以让前端请求 `/api/some-endpoint`,而实际调用的目标服务位于其他名上。对于 iframe 加载外部资源同样适用,只需调整加载链接指向本地代理即可[^4]。 --- #### 方法四:WebSocket 协议替代传统 HTTP 请求 虽然 WebSocket 并不是直接针对 iframe 设计的技术手段,但它完全绕过了传统的同源限制政策。假如业务需求允许的话,考虑采用 WebSockets 替代常规 AJAX 或者 fetch API 完成交互过程不失为另一种创新思路。 注意:该方式更适合实时通讯类应用场合,并不适合所有类型的项目迁移改造工作。 --- ### 总结 综上所述,推荐优先尝试基于标准的安全技术——即利用 `postMessage` 进行父子帧间的数据传输;其次再评估是否有必要引入额外基础设施层面上的支持措施像 NGINX Proxy Server 等工具辅助完成任务。每种办法都有各自适应范围以及局限之处,请结合具体应用场景权衡利弊后再做决定。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值