iframe实现跨域请求

1,118 阅读4分钟

iframe标签

iframe一般用来包含别的页面,iframe标签元素会创建包含另外一个文档的内联框架。当我们需要在一个网页里,嵌套另外一个网页,或者广告等,就可以使用iframe。使用iframe的好处是,主页的css样式是不会影响到iframe里面的样式,它也不会影响主页CSS样式。一个页面可以有多个iframe,但是它能耗高。

在一个网页中的iframe标签是局部刷新,不会刷新整个页面。

iframe出现安全问题有两个方面,一个是你的网页被别人iframe,一个是你iframe别人的网页。

前端可以使用window.top来防止你的网页被iframe。

try{
  top.location.hostname; //检测是否出错
  //如果没有出错,则降级处理
  //允许同源请求,判断域名
  if (top.location.hostname != window.location.hostname) { 
    top.location.href =window.location.href;//限定该网页不能嵌套在任意网页内
  }
}
catch(e){
  top.location.href = window.location.href;
}

后端服务器中X-Frame-Options相应头,主要是描述服务器的网页资源的iframe权限。

DENY:当前页面不能被嵌套iframe里,即便是在相同域名的页面中嵌套也不允许,也不允许网页中有嵌套iframe

SAMEORIGIN:iframe页面的地址只能为同源域名下的页面,只允许同源请求

ALLOW-FROM:可以在指定的origin url的iframe中加载,只允许指定网页的iframe请求

iframe标签的属性

src:规定在iframe标签中显示的文档的 URL,可以是页面地址也可以是图片,音频,视频的地址(必选)

width:框架作为一个普通元素的宽度,建议使用css设置(必选)

height:框架作为一个普通元素的高度,建议在使用css设置(必选)

scrolling:yes,no,auto(默认值)。规定是否在iframe标签中显示滚动条。

frameborder:1(默认值,就是显示边框),0(不显示边框)。规定是否显示 iframe标签周围的边框。

name:规定iframe的名称,可用于利用a标签的target来对应iframe的name以及通过window.frames[name]来获取iframe对象

allowtransparency:true or false,是否允许iframe设置为透明,默认为false

allowfullscreen:true or false,是否允许iframe全屏,默认为false

sandbox:用来给指定iframe设置一个沙盒模型限制iframe的权限

<iframe sandbox src=""></iframe>
这样会对iframe页面进行以下一系列的限制:

1.script脚本不能执行

  1. 不能发送ajax请求

  2. 不能使用本地存储,即localStorage,cookie等

  3. 不能创建新的弹窗和window

  4. 不能发送表单

  5. 不能加载额外插件比如flash等

常见的配置项:

<iframe sandbox="allow-forms allow-same-origin allow-scripts" src=""></iframe>

1.allow-forms:允许进行提交表单

2.allow-scripts:允许运行执行脚本

3.allow-same-origin:允许同域请求,比如ajax

4.allow-top-navigation:允许iframe能够主导window.top进行页面跳转

5.allow-popups:允许iframe中弹出新窗口,比如,window.open,target="_blank"

6.allow-pointer-lock:在iframe中可以锁定鼠标,主要和鼠标锁定有关

获取iframe里的内容

主要的两个就是contentWindow,和contentDocument iframe.contentWindow, 获取iframe的window对象 iframe.contentDocument, 获取iframe的document对象 这两个API只是DOM节点提供的方式(需要用DOM操作先获取iframe元素)

<body>
    <iframe src="" frameborder="0" id="if"></iframe>
    <script>
        let iframe=document.getElementById("if");
        let idocu=iframe.contentDocument;
        console.log(iframe.contentWindow,11);
        console.log(idocu);
        console.log(window.frames["if"],222);
    
    </script>
</body>

image.png

在iframe中获取父级内容

在同域下,父页面可以获取子iframe的内容,子iframe同样也能操作父页面内容。在iframe中,可以通过在window上挂载的几个API进行获取。

window.parent 获取上一级的window对象,如果还是iframe则是该iframe的window对象
window.top 获取最顶级容器的window对象,即,就是你打开页面的文档
window.self 返回自身window的引用。

image.png

iframe1.self === iframe1
iframe1.parent === iframe2
iframe2.parent === window
iframe1.top === window

iframe实现跨域请求

一般会使用iframe来进行父子页面的通信,对于主域相同子域不同的两个页面,我们可以通过document.domain + iframe来解决跨域请求问题。就是将某一方使用iframe嵌套在另一方页面

主域相同,不同子域之间的跨域请求 例如:http://www.aotu.com/a.htmlhttp://sy.aotu.com/b.html

默认情况下document.domain是指window.location.hostname。可以手动更改,但是最多只能设置为主域名。通常,主域名就是指不带www的hostname,比如:aotu.com,baidu.com。 如果,带上www或者其他的前缀,就是二级域名或者多级域名。

iframe跨域的流程:b.html是以iframe的形式嵌套在a.html中

1.创建iframe,在a.html文件中,动态创建iframe元素

2.为了让用户无法看到这个iframe元素,需要使用CSS将其移出可视区或者允许设置为透明以及隐藏不可见

3 设置domain,为了保证a.html与b.html的访问都能够进行请求,需要为两个文件定义domain,即将document.domain设置为“主域名”。document.domain = aotu.com""指定相同的主域,然后两个文档就可以进行交互。

4 数据操作,在a.html文件当中获取b.html文件,就是动态创建的iframe元素获取它的window对象。就可以在a.html来操纵b.html

a.html

document.domain = "aotu.com";
let if = document.createElement('iframe');
if.src = "http://sy.aotu.com/b.html";
if.style.display = "none";
document.body.appendChild(if);
if.onload = function(){
    let doc = if.contentDocument || if.contentWindow.document;
    // 在这里操纵b.html
};

在b.html中同样设置document.domain = "aotu.com";