基于iframe的跨域与更新父窗体地址栏的解决方案

1 需求介绍:

管理平台前端页面需要在当前前端框架结构基础上,在顶级导航中增加两个模块:首页、运维管理模块,以此接入运维平台提供的页面。在访问到内部某个页面后,希望父窗体的地址栏跟随子窗体内部src,同时更新父窗体的地址栏,再刷新页面可以保持在当前访问的页面,同时可以分享链接。

2 解决方法:

2.1 简单使用iframe:

可以使用iframe:直接在页面嵌套iframe标签指定src就可以了,最简单的使用方法如下:

<iframe src="xxxx"></iframe>

在此基础上,可以在iframe中设置一些参数,使其更符合页面的需求:

可参考iframe常用属性:

1.frameborder:是否显示边框,1(yes),0(no)

2.height:框架作为一个普通元素的高度,建议在使用css设置。

3.width:框架作为一个普通元素的宽度,建议使用css设置。

4.name:框架的名称,window.frames[name]时专用的属性。

5.scrolling:框架的是否滚动。yes,no,auto。

6.src:内框架的地址,可以使页面地址,也可以是图片的地址。

这样在代码中可以设定iframe的src,来接入运维平台的页面。

具体实现方式可以用原生iframe标签,或者react的react-iframe,我两种都试过,都可以使用,但考虑到后续要实现诸如“内部页面刷新保持”的效果,建议还是直接使用原生的iframe标签,因为要用到iframe的onload事件。

2.2 遇到的问题

我是在当前开发的前端框架基础上,去嵌套其他平台的前端页面。管理平台的前端使用的是react框架,要接入运维平台页面首页、虚拟机、宿主机等10个模块。运维平台提供的是去掉顶部导航的页面的地址,即只包含内容,这样可以直接使用管理平台的顶部导航,在内容区域嵌套运维平台的页面,让用户在使用时,感受不到两个平台间的跳转。

在管理平台接入运维平台的页面时,我是这样设计的路由:给每个模块一个地址,以其中的一个模块----虚拟机模块为例,虚拟机模块下包括虚拟机管理页面、虚拟机创建页面和虚拟机详情页面。管理平台给虚拟机模块的设定的路径是:

“/op/opManagement/compute/vm”

这样虚拟机模块下的所有页面使用的都是这个路径。另外在iframe中设定的src地址,指向的是运维平台虚拟机的管理页面。这样在顶级导航中点击“私有网络”,便可跳转到运维平台的管理页面。在该页面,又可从虚拟机管理页面跳转到虚拟机创建页面、虚拟机详情页面,甚至跳转到母机模块的相关页面。从我们管理平台的角度来说是没有问题的,管理提供了一个入口地址,可以正常接入运维平台的页面。运维平台内部页面中还可调整到其他页面,我们就不做管理了。

但是这样简单的实现方式,在体验上存在一个问题:当用户正常进入虚拟机管理页面后,由于可以从页面内容跳转到其他页面,例如跳转到某个详情页面。当用户过一会儿刷新页面后会发现:没有按照预期停留在详情页面,而是又回到了虚拟机管理页面了!

这是因为前面介绍过,无论是虚拟机管理页面、虚拟机创建页面,还是虚拟机详情页面,在管理平台上设定的路由都是“/op/opManagement/compute/vm”,且这个指向的又是虚拟机管理页面,所以无论上次停留在什么页面,再刷新都是会回到虚拟机管理页面。这是根据路由设定的,从技术角度讲没有问题。

但从用户体验上来说,这里的体验会让用户产生不舒服的感觉:明明上次还停留在虚拟机详情页面,怎么我一刷新跑到了其他页面上呢?而且我想把这个详情页面的链接分享给其他同事看看,怎么打开却是虚拟机管理页面呢?我想用浏览器的回退、前进按钮,怎么和我预想的不一样呢?

2.3 解决iframe实现刷新页面保持

针对上面的问题,我的解决方法是:第一,每次在iframe内部页面跳转后,获取到iframe内跳转后最新的src值。第二,然后根据这个src值,修改管理平台地址栏的url。下面是具体解决方案:

要监听iframe的src的变化,可使用onload事件:

<iframe src="xxx" onLoad="alert('Test');"></iframe>

src变化,onLoad会被调用。但有一个前提,src和你的父窗口的地址必须是同源的,也就是不能跨域。

但实际上管理平台的页面和运维平台的页面并不是同源的,所以首先要解决的是跨域问题。

解决跨域的方法有很多种,这里由于管理平台的主域是“oa.com”,运维平台的主域也是“oa.com”,所以采用document.domain来跨域。这里需要管理平台和运维平台一起进行修改:在项目的入口文件中设置:

document.domain=”oa.com”;

这样便解决了跨域的问题。

然后在每次ifrmae内部src变化时,便会调用onLoad()。内部在window.location的hash值变化后,获取子窗体的href值,再对父窗体的地址栏做修改。以虚拟机模块的代码为例,由于从虚拟机页面还有可能跳转到母机模块,这里也要考虑到:

如果是在获取到子窗体的src后,以window.location.href = xxx;的方式来修改父窗体,是可以达到更新父窗体地址栏src的效果,但会在修改地址栏的同时刷新页面。实际上iframe内部页面点击链接后会发生跳转的动作,如果这时又再次刷新页面,让用户本来已经看到页面跳转后,再看到重新刷新页面,从用户体验上考虑并不好。因此这里要实现的是修改地址栏,但不要实现页面的刷新。

这里采用H5的history.replaceState(state,title,url)方法,该方法只会更新地址栏的url,但不会刷新页面,正符合需求。

这样每次iframe内部的src发生变化后,都会相应修改父窗体的地址栏,但又不会去刷新当前页面,效果上看起来就像是在自己的页面中操作,感受不到跨站点的问题。

每次刷新页面,在页面初始化时,就根据当前父窗体的地址栏中的url去得到属于运维平台的location.search值,用这个值修改iframe的src值,达到每次刷新页面,都可以根据当前地址栏的url,接入运维平台的对应页面。这里还是以虚拟机模块为例:

至此,我以虚拟机模块为例,实现了跨站点接入页面,并实现iframe内部src改变后,修改管理平台地址栏url的目的。以此可以保证了再刷新页面后,可保持在上次打开的页面,这样便于分享链接、使用回退、前进按钮。

3 相关知识点

3.1 window.location的属性

window.location对象的其他属性包括:

· hash 哈希值。设置或返回从井号 (#) 开始到 URL结束的值

· hostname 设置或返回当前 URL 的主机名。

· host 设置或返回主机名和当前 URL 的端口号。

· href 设置或返回完整的 URL。

· pathname 设置或返回当前 URL 的路径部分。

· port 设置或返回当前 URL 的端口号。若port的值为空字符串,其实,该网站监听的是默认的80端口。

· protocol 设置或返回当前 URL 的协议。协议有http:,https:,file:等

· search 查询字符串。设置或返回从问号 (?) 开始的 URL(查询部分)。多个查询参数之间用&分隔,如?a=b&c=d。

3.2 常见的跨域方法

3.2.1 同源策略

是一个浏览器的安全策略,同源是指:协议、域名、端口都相同的页面。只要有一个不同,就会受到同源策略的限制。

同源策略:不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源。所以a.com下的js脚本采用ajax读取b.com里面的文件数据是会报错的。

3.2.2常见的跨域方法

本文主要是在一个具体问题中,根据问题的具体情况,采用了document.domain的方式解决跨域问题,其他跨域的方法,诸如图像Ping、JSONP、window.name、H5的postMessage方法、CORS的方法,有兴趣的童鞋可以自行google一下。

3.3 history.replaceState()

作用:可修改浏览历史中当前纪录

使用:history.replaceState(data,title,url);

具体参数的含义可自行google。

4 小结

本文主要是以一个前端项目中实际遇到的需求为出发点,基于项目的具体情况,以用户体验为依归,提出了一套具体的解决方案。大家如果有更好的方案可以互相讨论一下。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏数据小魔方

异步加载的基本逻辑与浏览器抓包一般流程

本篇内容不涉及任何R语言或者Python代码实现,仅从异步加载的逻辑实现过程以及浏览器抓包分析的角度来给大家分享一下个人近期学习爬虫的一些心得。 涉及到的工具有...

36240
来自专栏DeveWork

WordPress自定义栏目运用实例III:添加原创/转载文章不同版权声明

这里是WordPress自定义栏目运用实例系列第三讲,为大家带来用自定义栏目添加原创/转载文章不同版权声明。跟本上,这个与之前的《WordPress自定义栏目运...

19680
来自专栏web

vue.js环境搭建

25930
来自专栏编程

再撩Python

如果你觉得很复杂,不要慌张,它本来就很复杂。 如果你觉得很简单,不要慌张,它本来就很简单。 --小浪 1、起手 还要把Python的开发环境说说。 2、Pyth...

204100
来自专栏前端桃园

从0开始发布一个无依赖、高质量的键盘npm包

17140
来自专栏沈唁志

使用WeeChat进行Internet中继聊天

WeeChat是一个用C语言编写的基于终端的多平台Internet中继聊天(IRC)客户端.Weechat旨在灵活和可扩展,因此具有用不同语言编写的各种插件,包...

1.5K30
来自专栏前端杂货铺

XSS分析及预防

XSS(Cross Site Scripting),又称跨站脚本,XSS的重点不在于跨站点,而是在于脚本的执行。在WEB前端应用日益发展的今天,XSS漏洞尤其容...

37370
来自专栏FreeBuf

记一次利用BLIND OOB XXE漏洞获取文件系统访问权限的测试

今天,我要和大家分享的是,我在某个邀请漏洞测试项目中,发现Bind OOB XXE漏洞的方法。由于涉及隐私,以下文章中涉及网站域名的部分我已作了编辑隐藏,敬请见...

32150
来自专栏张戈的专栏

WordPress评论ajax动态加载,解决静态缓存下评论不更新问题

这是一个历史遗留问题,自从博客部署了 PHP 纯静态缓存之后,所有页面都是 html 静态内容了,而且在七牛 CDN 静态分离之后,速度更是达到极致! ? 不过...

41060
来自专栏月色的自留地

golang子进程的启动和停止,mac与linux的区别

28650

扫码关注云+社区

领取腾讯云代金券