一、业务场景
公司没有单独的第三方文件服务器,因此用自己公司的其中一台机来做文件服务器。某个业务模块跟文件服务器不是同一台主机,可以实现不会抢占带宽。
业务系统需要做文件上传操作,把文件上传到文件服务器。
二、解决方案
考虑到这里的操作场景很单一,在业务系统访问文件服务器也就是调用上传下载接口而已,因此采用在业务系统内嵌一个iframe,并将这个iframe大小调成业务系统中的文件上传按钮大小一致,设置层级比上传按钮的层级低,并设置为不可见。
在iframe的内容也只有一个上传按钮,不同的是这个按钮是在另外域名下的。它们之间的关系是这样的:
这就使得用户在点击业务系统中的文件上传按钮实际上就是点击了iframe里面的文件上传按钮。
那么现在我们要解决的一个问题就是,业务当前所在的window怎么知道iframe里面的window的上传进度呢?我们需要在业务系统中更新文件上传进度,这就涉及到了两个不同window之间的通信。那两个不同域名的window是怎么通信的?
三、iframe跨域之间的通信
1、发送消息
postMessage(message, targetOrigin),该方法接受两个必传参数,message是将要发送到其他 window的数据,targetOrigin指定哪些窗口能接收到消息事件,其值可以是 ***** (表示无限制)或者一个 URI。
<iframe
id="fileIframe"
ref="fileIframe"
:src="iframeUrl"
frameborder="0"
style="opacity: 0.01;z-index: 1;"
></iframe>
下面我们专门写一个方法来发送消息
sendMessage(eventParams) {
const iframeWin = this.$refs.fileIframe.contentWindow;
iframeWin.postMessage(eventParams, 'https://www.aa.com');
}
2、接收消息
既然一方发送了消息,另一方就要进行接收,接收使用message(e)
window.addEventListener('message', function (e) { // 监听 message 事件
if (e.origin !== "https://www.aa.com") { // 安全性验证,验证消息来源地址
return;
}
console.log(e.data); // 接收传过来的数据
});
四、使用iframe要考虑哪些问题
1、性能问题
-
iframe会阻塞主页面的onload事件
-
搜索引擎的检索程序无法解读这种页面,不利于SEO
-
iframe和主页面共享连接池,而浏览器对相同域的连接有限制,会影响页面的并行加载
针对以上问题,最好可以通过js动态的给iframe添加src属性值,比如:
<!-- a.html -->
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div style="display:none"><iframe id="tsrc"></iframe></div>
<input id="button1" type="button" value="异步加载script" onclick="testClick()"/>
</body>
<script>
function testClick()
{
document.getElementById("tsrc").src="b.html"
}
</script>
</html>
<!-- b.html -->
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
</body>
<script>
alert('我是异步script');
</script>
</html>
一般情况下,不建议是用iframe,除非被嵌套的页面不复杂,业务场景简单。
2、安全问题
iframe可以实现跨域访问,这就意味着别人可以把你的网页嵌套到别人的页面上,通过各种手段准备好验证的信息去调用你的接口
为了防止网站被钓鱼,可以使用window.top来防止你的网页被iframe.
if(window != window.top){
window.top.location.href = correctURL;
}
如果你想引用同域的框架的话,可以判断域名。
if (top.location.host != window.location.host) {
top.location.href = window.location.href;
}