你的浏览器不支持canvas

Enjoy life!

javasript - 跨域 - location.hash + iframe

Date: Author: JM

本文章采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议 进行许可。

一、location.hash与iframe实现跨域

relationship-map

1.1 原理

  • iframe + hash 实现跨域。

1.2 步骤

  • 假设http://127.0.0.1:3001/a.htmlhttp://127.0.0.1:3002/b.html需要实现通信。
  • http://127.0.0.1:3001/a.html
  1. http://127.0.0.1:3001/a.html下嵌入一个iframe,其src为:http://127.0.0.1:3002/b.html
  2. a.html发送数据数据给b.html,并修改iframesrchttp://127.0.0.1:3002/b.html#pro#pro就是location.hash
  3. a.html在监听到url变化,并进行相应的操作
    • 即:a.html通过urlhash就可以拿到b.html传过来的数据

http://127.0.0.1:3002/b.html

  1. b.html监听到url的变化,触发相应的操作
    • b.html传送数据到a.html,由于两个页面不在同一个域下IEChrome不允许修改parent.location.hash的值,所以要借助于父窗口域名下的一个代理iframe
  2. b.html下创建一个隐藏iframe,其src为:http://127.0.0.1:3001/proxy.html,并附加上要传送的数据,即iframe完整的src是:http://127.0.0.1:3001/proxy.html#data
try {  
    parent.location.hash = 'data';  
} catch (e) {  
    // ie、chrome的安全机制无法修改parent.location.hash, 
     // 创建一个iframe
    var ifrproxy = document.createElement('iframe');
     // 隐藏iframe
    ifrproxy.style.display = 'none';  
    ifrproxy.src = "http://www.baidu.com/proxy.html#data";  
    // 将iframe添加到页面,资源才可以加载
    document.body.appendChild(ifrproxy);  
}

http://127.0.0.1:3001/proxy.html

  1. proxy.html监听到url的变化,就可以修改与其同域a.htmlurl
//因为parent.parent(即http://127.0.0.1:3001/a.html)和http://127.0.0.1:3001/proxy.html属于同一个域,所以可以改变其location.hash的值  
parent.parent.location.hash = self.location.hash.substring(1);

1.3 location.hash的注意事项

  • HTTP请求过程中不会携带hash,所以修改hash不会产生HTTP请求
  • 设置 location.hash 会在这些浏览器中生成一条新的历史记录

二、hashchange事件

  • hashchange事件:在 URL 的参数列表(及 URL 中“#”号后面的所有字符串)发生变化时通知开发人员。
    • 新增这个事件的原因:在 Ajax 应用中,开发人员经常要利用 URL 参数列表来保存状态或导航信息。
    • 支持 hashchange 事件的浏览器有 IE8+、Firefox 3.6+、Safari 5+、Chrome 和 Opera 10.6+。
      • 只有 Firefox 6+、Chrome 和 Opera 支持 oldURLnewURL 属性。
  • hashchange 事件处理程序只能挂在 window对象下,然后 URL 参数列表只要变化就会调用它。
    • event 对象应该额外包含两个属性:
      • oldURL:保存着参数列表变化前的完整 URL
      • newURL:存着参数列表变化后的完整 URL
EventUtil.addHandler(window, "hashchange", function(event){
 alert("Old URL: " + event.oldURL + "\nNew URL: " + event.newURL);
})
 
//最好是使用 location对象来确定当前的参数列表。
EventUtil.addHandler(window, "hashchange", function(event){
 alert("Current hash: " + location.hash);
}); 
  • 检测浏览器是否支持 hashchange 事件
var isSupported = ("onhashchange" in window); //这里有 bug 

// 如果 IE8 是在 IE7 文档模式下运行,即使功能无效它也会返回 true。
var isSupported = ("onhashchange" in window) && (document.documentMode === undefined || document.documentMode > 7); 

三、总结

  • location.hashiframe跨域存在的问题:
    1. 这个方式的通信会造成一些不必要的浏览器历史记录
    2. 有些浏览器不支持onhashchange事件,需要轮询来获知URL的改变
    3. 数据直接暴露在了url
    4. 数据容量和类型都有限

对于本文内容有问题或建议的小伙伴,欢迎在文章底部留言交流讨论。