前端跨域知识简介

前端跨域知识简介

灵感

差不多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 条评论
登录 后参与评论

相关文章

来自专栏葡萄城控件技术团队

React Native基础&入门教程:以一个To Do List小例子,看props和state

在上篇中,我们介绍了什么是Flexbox布局,以及如何使用Flexbox布局。还没有看过的小伙伴欢迎回到文章列表点击查看之前的文章了解。

693
来自专栏Golang语言社区

从websocket看go的应用

Go是互联网时代的通用编程语言。这样它就和命令行时代的C语言、图示界面时代的C++、以及互联网早期的Java语言等有不同的侧重。它强调保持自身的精巧和独立,从而...

2916
来自专栏Crossin的编程教室

Python爬虫:一些常用的爬虫技巧总结

转自:开源中国 http://my.oschina.net/jhao104/blog/647308 用python也差不多一年多了,python应用最多的场景...

2764
来自专栏风中追风

一次URL输入域名按下回车到底发生了什么?

1、 浏览器的url输入栏发起一个请求,浏览器首先会看自己缓存中有没有对应的ip地址,如果有的话

3436
来自专栏Golang语言社区

从websocket看go的应用

Go是互联网时代的通用编程语言。这样它就和命令行时代的C语言、图示界面时代的C++、以及互联网早期的Java语言等有不同的侧重。它强调保持自身的精巧和独立,从而...

3537
来自专栏专注于主流技术和业务

axios2教程

axios 是一个基于 promise 的 HTTP 库,用于浏览器和node.js的http客户端,支持拦截请求和响应,自动转换 JSON 数据, 客户端支持...

1722
来自专栏枕边书

用C写一个web服务器(四) CGI协议

前言 时隔一个多月,终于又有时间来更新我的服务器了,这次更新主要实现一下 CGI 协议。 先放上GitHub链接 tinyServer-GitHub-枕边书 作...

2796
来自专栏Kiba518

【我们一起写框架】MVVM的WPF框架之绑定(二)

上一篇我们已经一起编写了框架的基础结构,并且实现了ViewModel反向控制Xaml窗体。

782
来自专栏吴伟祥

RESTful接口入门 转

从下面的图片可以看出,当我们需要把相同的数据展示到不同的界面上时,提供一个可以访问后台的接口,前台只负责将数据友好的,华丽的展示出来即可。而不需要为每一个前台都...

873
来自专栏流柯技术学院

Jmeter对基于websocket协议的压力测试

WebSocket protocol 是HTML5一种新的协议。它实现了浏览器与服务器全双工通信(full-duplex)。

2643

扫码关注云+社区