iframe解决文件上传跨域问题

672 阅读3分钟

一、业务场景

公司没有单独的第三方文件服务器,因此用自己公司的其中一台机来做文件服务器。某个业务模块跟文件服务器不是同一台主机,可以实现不会抢占带宽。

业务系统需要做文件上传操作,把文件上传到文件服务器。

二、解决方案

考虑到这里的操作场景很单一,在业务系统访问文件服务器也就是调用上传下载接口而已,因此采用在业务系统内嵌一个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;
}