前端跨域知识简介

前端跨域知识简介

灵感

差不多2年前,由于业务需要,了解各种各样不同的跨域方式。但由于各种方式千奇百怪,我觉得有必要将各种方法封装起来,方便使用,弄了个简单的跨域使用库,里面包含各种跨域的使用函数,都存放在steamer-cross v1.0分支里。但2年过后,IE8以下的浏览器已经逐渐淡出市场,基本上跨域的方案可以由postMessage一统天下,于是在MessengerJS启发下,自己写了一个steamer-cross v2.0版本,更灵活的用法,且兼顾父子窗口之间互相传递数据。

v1.0版本可能有bug,仅供学习参考,v2.0已写测试样例,可以test文件夹中看到,文档不清楚的地方,也可以参考test/index.html的写法。

本文主不会详细述说各种方法的具体实现,具体的办法可以点击后文参考资料里面的三篇文章。本文只会提及实现过程中的一些坑,以及框架的实现办法。具体的实现方法,可以参考steamer-cross v1.0版本中的文件,各种办法的实现,可以看对应文件夹里面的文件。

跨域方法 -- 单向

jsonp

这是最直观的办法,只需要一个页面,在页面内包含一个指向数据页面的script tag,然后在src后面多加一个回调函数即可以获取数据。

cross origin resource sharing (cors)

这个办法前后端都涉及,因此前端的同学需要后端的配合。其实质只是一个ajax,可以接收除了post和get之后的其它服务器请求例如put。后端需要修改的是.htaccess文件。加入以下一句

Header set Access-Control-Allow-Origin *

符号*代表接收任意的HTTP请求,你也可以通过修改,限制接受请求的域名或者IP地址。

另外一个隐藏坑是,ie10以下的浏览器是不支持的。值得注意的是,ie8和ie9是通过XDomainRequest来进行CORS通信的。XDomainRequest同样支持get和post方法。对象详细内容请见参考资料。

XDomainRequest的另一个坑是,当发送POST请求的时候,无法设置Header,如

xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");

这可能导致后台没法辨认POST数据。如果是PHP的话,后台需要特殊的处理,例如

if(isset($HTTP_RAW_POST_DATA))
{
    parse_str($HTTP_RAW_POST_DATA, $output);
    echo json_encode($output);
}

CORS支持情况:Chrome 4 , Firefox 3.5 , IE 8~9(XDomainRequest), IE 10+ , Opera 12 , Safari

location.hash

这个办法坑比较多,网上的办法会有些问题。这个办法需要三个页面,分别是主调用页(index.html), 数据页(data.html),和代理页(proxy.html)。实质的结构是,index.html里有一个iframe指向data.html,而data.html里又有一个iframe指向proxy.html。要注意的是,index.html和proxy.html主域和子域都相同,只有data.html是异域,因此当data.html生成数据时,将数据放在proxy.html链接的hash(#)后面,然后再由proxy.html里的代码通过parent.parent这样的调用,将数据放到proxy.html的祖父index.html的链接上面。

大多数教程都是停留在这一步。这是不够的,还需要在index.html里面设置一个setInterval去监听index.html中#的变化,进而获取数据。据说有些高端浏览器里面可以直接用hashchange来监听,但低端的话最好还是用setInterval。因此框架里面用setInterval实现。

window.name

由于window.name在iframe的src的变化时不会改变,所以这个办法也可以用于跨域。这个方式虽然也需要跟location.hash也需要三个页面,但proxy.html的作用非常次要。由于data.html能够直接对window.name写值,因此写值完毕后,只需要将src改成与index.html主域和子域一致的页面,就可以让index.html直接调用了。也有不需要proxy页面的写法,将iframe的src写成"about:blank;"就可以了。

跨域方法 -- 双向

document.domain

这个办法对于主调用页(index.html)和数据页(data.html)而言是双向的,即两个页面都可以得到对方的数据(主要是DOM元素)。实质就是index.html包含一个指向data.html的iframe,然后在data.html中改变document.domain,使之和index.html的document.domain是一样的,这样就可以使两个页面互相调用对方的数据。唯一的缺点是只能应用于子域不同,但主域相同的两个页面。

postMessage

网上大部份教程都只教从index.html传数据到data.html。其实data.html也可以发数据到index.html。实现方法一样,只要在data.html里面发送的地址跟index.html的地址一样就可以了。否则浏览器会报错。这是比较优秀的一个办法,缺点是旧式浏览器并不支持。

window.navigator

这是ie6和ie7的一个安全bug。目前似乎还没有补丁打上,所以主页面和iframe页面之间可以自由调用。

参考资料

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Jerry的SAP技术分享

使用JavaScript调用手机平台上的原生API

我之前曾经写过一篇文章使用Cordova将您的前端JavaScript应用打包成手机原生应用,介绍了如何使用Cordova框架将您的用JavaScript和HT...

942
来自专栏JetpropelledSnake

Web前端学习笔记之前端跨域知识总结

相信每一个前端er对于跨域这两个字都不会陌生,在实际项目中应用也是比较多的。但跨域方法的多种多样实在让人目不暇接。老规矩,碰到这种情况,就只能自己总结一篇博客,...

593
来自专栏我和PYTHON有个约会

Django来敲门~第一部分【6.1 视图函数】

在我们创建好的应用polls/中,可以定义视图函数,专门用于接收和响应URL请求操作的函数; 该函数默认第一个参数接收的就是一个请求对象HttpRequest...

521
来自专栏零基础使用Django2.0.1打造在线教育网站

零基础使用Django2.0.1打造在线教育网站(十七):我要学习配置

努力与运动兼备~~~有任何问题可以加我好友或者关注微信公众号,欢迎交流,我们一起进步!

121
来自专栏LIN_ZONE

laravel5.5+vue+Element-ui+vux环境搭建(webpack+laravelMix)(转)

本教程例子可到GitHub 上下载 Laravel5.5-Vue-Element-ui-Vux

872
来自专栏更流畅、简洁的软件开发方式

使用IE6看老赵的博客——比较完美版(可以在线查看、回复)

  上一个版本主要是测试一下我的想法,也是熟悉一下jQuery,代码这个东东不动手写一下是很难弄明白的。   有想法,写代码,出现错误,修改错误 = 不断进步。...

1928
来自专栏有趣的django

Django搭建blog网站(一)

一、前言 1.1.环境 python版本:3.6 Django版本:1.11.6 1.2.预览效果 最终搭建的blog的样子,基本上满足需求了。框架搭好了,至于...

4578
来自专栏java相关

dotfiles项目

472
来自专栏青枫的专栏

ajax学习小结

691
来自专栏程序员宝库

IntelliJ IDEA 教程设置讲解

IntelliJ在业界被公认为最好的java开发工具之一,尤其在智能代码助手、代码自动提示、重构、J2EE支持、Ant、JUnit、CVS整合、代码审查、 创新...

694

扫码关注云+社区