JavaScript中的跨域详解(内附源码)
来源:互联网 发布:diy在线定制系统 源码 编辑:程序博客网 时间:2024/05/22 14:12
什么是跨域?
什么是跨域?
所谓跨域,就是如果在不同的域名下面存在数据交互,这个时候就会存在跨域的问题,这里要说明的是在同一个网站不同的文件夹下的数据交互是不存在跨域问题的。
哪些情况下存在跨域问题?
主域和子域之间会存在跨域问题(比如
www.a.com
和www.a.b.com
)。不同的域名存在跨域问题,哪怕这两个域名指向的是同一个
ip
地址。
为什么 ajax 不可以跨域?
因为 ajax
是通过 XMLHttpRequest
这个对象来进行数据之间的交互的,而 XMLHttpRequest
为了安全起见是不允许跨域交互数据,所以 ajax
是不可以跨域的。
跨域问题的几种解决方式?
jsonp
原理:动态插入 script
标签,通过 script
标签引入一个js
文件,这个js
文件载入成功后会执行我们在 url
参数中指定的函数,并且会把我们需要的 json
数据作为参数传入。
由于同源策略的限制,XmlHttpRequest
只允许请求当前源(域名、协议、端口)的资源,为了实现跨域请求,可以通过script
标签实现跨域请求,然后在服务端输出 JSON
数据并执行回调函数,从而解决了跨域的数据请求。
优点是兼容性好,简单易用,支持浏览器与服务器双向通信。缺点是只支持GET请求。
JSONP:json+padding(内填充),顾名思义,就是把JSON填充到一个盒子里
jsonp
有一个缺点就是只能单域操作,就是我们不可以通过本网站去修改其他网站的数据。
使用 jsonp
来进行跨域是平时比较常用的,用 script
标签的形式,script
标签不存在跨域的问题,(不仅如此,我们还发现凡是拥有“src”这个属性的标签都拥有跨域的能力,比如<script>
、<img>
、<iframe>
)我们也把它统称为 jsonp
的形式。
我们可以把 script
里面的 src
当做请求的地址,你要知道 script
标签不是仅仅只能请求 js
文件,比如说它还可以请求 php
。只要是这个页面运算完返回的结果是 json
或者是 js
它就不会有问题。
实例一:
</head><body><script type="text/javascript"> //a.com</script><!-- 假如我们这里引入的是b网站的php文件, a网站的数据就可以通过 src 传送到 b 网站,a 网站的数据是加到问号后面的,然后数据在 b 网站进行运算,最终把返回的结果输出出来,那我们在 a 网站中就可以调用到b网站的数据了--><script type="text/javascript" src="b.php?key=value&key2=value2"></script></body>
实例二:
(jsonp.html)<body><script type="text/javascript"> //a.com //注意这里名字要一样,即 box function box(json){ //这个时候在 a 网站下我们就可以取到这个 name 值了 alert(json.name); }</script><script type="text/javascript" src="1.jsonp.js"></script></body>
(jsonp.js)//b.com//我把数据写到盒子里面之后,我这个数据是在 b 网站的地址下面//的,而我们要调用的时候就可以利用回调的原理进行调用。box({name : 'laowang'});
效果展示 || 源代码
动态创建 jsonp
(jsonp.html)<script type="text/javascript"> function createJs(sUrl){ var oScript = document.createElement('script'); oScript.type = 'text/javascript'; oScript.src = sUrl; document.getElementsByTagName('head')[0].appendChild(oScript); } createJs('jsonp.js?callbcak=box'); //这个 box 必须和 jsonp 中的 box 一致,但是有的时候, //你不知道这个名字是什么,那我们就可以自己写一个参数加进去 //从而让自己来来控制这个名字 //即:?callbcak=box function box(json){ alert(json.name); }</script>
(jsonp.js)box({name : 'laowang'});
效果展示 || 源代码
当然,jquery
中也提供了封装好的 jsonp
方法。最后再提一句,一般不会选择在页面上直接引入 <script>
这种方式,而是在 js
中动态生成 <script>
节点。
CORS
即使浏览器对 CORS 的支持程度并不都一样,但所有浏览器都支持简单的(非 Perflight
和 不带凭据的)请求,因此有必要实现一个跨浏览器的方案。检测 XHR 是否支持 CORS 的最简单的方式,就是检查是否存在 withCredentials
属性。在结合检测 XDomainRequest
对象是否存在,就可以兼顾所有的浏览器了。
具体代码如下:
function createCORSRequest(method,url){ var xhr = new XMLHttpRequest(); if("withCredentials" in xhr){ xhr.open(method,url,true); } else if(typeof XDomainRequest != "undefined"){ xhr = new XDomainRequest(); xhr.open(method,url); } else { xhr = null; } return xhr;}//由于无论是同源请求还是跨域请求都是用相同的接口,因此对于本地//资源,最好使用相对rul,再访问远程资源时在使用绝对url。var request = createCORSRequest(method,url);if(request){ request.onload = function(){ //对 request.responseText 进行处理 }; request.send();}
在 createCORSRequest()
返回的对象中,在所有的浏览器中都可以使用下列方法或者属性:
abort() : 用于停止正在进行的请求onerror : 用于代替 onreadystatechange 检测错误onload : 用于代替 onreadystatechange 检测成功responseText : 用于取得相应内容send() : 用于发送请求
location.hash
可以利用 location.hash
值进行跨域,因为我们跨域无非就是发送一个请求,然后取得页面的数据。我们可以通过 iframe
利用 location.hash
来进行跨域操作。这个方法的优点就是可以进行双域操作。
原理:比如说我在 a
网站上嵌套了一个 b
网站的 iframe
这个时候,我们就可以把数据添加到用 script
标签引入的 php
的哈希值上,即 src="xxx.php#key1=value&key2=value2"
,哈希值加完之后不会改变页面的网址,这样可以把数据带到 b
网站,然后 b
网站就可以根据数据进行解析,返回数据,然后a
网站可以通过 parent.location.hash
来更新本页面的 hash
值,那这个时候 a
网站就可以获取到 b
网站上的数据了。
但是这个方法是另一个域下面的,为了安全起见,有的浏览器是不支持的,比如说 ie
和 chrome
,咱们没办法直接从另一个域上面找到它的父级,这样的话咱们就可以通过在 a
网站的页面当中再去创建一个 a
网站的页面。
比如说创建一个新的页面 yyy.html
,他也是 a
网站的,然后把数据添加到 a
网站的 yyy.html
这个页面中,添加号之后呢,这个时候我们就可以在 a
网站通过这个方法 parent.location.hash = self.location.hash
获取数据, 因为他们现在是同一个域下面的,这样子就可以通过改变hash
值,来进行这两个域之间的数据交互。
window.name
还可以用 window.name
来解决跨域的问题,这个是比较安全的,因为内容写到了 window.name
上,不会暴露出来。
window
对象有个 name
属性,该属性有个特征:即在一个窗口 (window)
的生命周期内,窗口载入的所有的页面都是共享一个 window.name
的,每个页面对 window.name
都有读写的权限,window.name
是持久存在一个窗口载入过的所有页面中的。
原理:现在有两个网站,这两个网站下面各有一个页面 www.a.com -->a1.html 和
www.b.com -->b1.html
,然后我们也是通过在 a
网站的 a1.html
下面创建一个 iframe
标签,然后 src
指定的就是 b
网站数据的 b1
这个页面,然后我们在 b
网站的 b1.html window.name = '数据';
下面去写数据就可以了。
写完之后,当 a1
加载完之后,我们在 b1
下面去创建 a1
的一个代理文件,www.b.com --> agent.html
,创建完之后,代理文件和 window.name
是共用数据的,这个时候当我再请求 a1.html
的时候,就可以通过代理来取到数据了。
这个和 hash
的原理其实是差不多的,都是在自己的域下面创建一个当前要用数据那个域的一个代理文件,然后再通过代理和当前文件在同一个域下的一个原则,然后把数据提交过去。
个人认为 window.name
的方法既不复杂,也能兼容到几乎所有浏览器,这真是极好的一种跨域方法。
document.domain
在子域和主域之间都设置 document.domain = '主域名的网址';
将子域和主域的 document.domain
设为同一个主域。前提条件:这两个域名必须属于同一个基础域名!而且所用的协议,端口都要一致,否则无法利用document.domain
进行跨域。
服务器代理
不同的域名下通过服务器代理解决:服务器代理是通过在服务器下面做这个对象XMLHttpRequest
的代理文件,然后服务器去做运算,他的优点是你可以做到任何你想要的数据交互,而它的缺点是会增大服务器的压力。
flash
flash
也可以解决跨域的问题。
postMessage
postMessage
是 html5
的方法,有兴趣的同学可以自己去看一下。
- JavaScript中的跨域详解(内附源码)
- Java之局部内部类和匿名内部类的区别详解(附源码)
- SilverLight浏览器交互之:Html页面通过Javascript调用SilverLight程序内方法(附源码)
- win32.多线程程序设计(内附源码)
- Ajax入门教程(内附源码实例)
- SilverLight浏览器交互之:SilverLight程序调用外部Html中的Javascript方法(附源码)
- VC++ MFC 画图 详解(附源码)
- Android CursorLoader实例详解(附源码)
- Qt之QLineEdit详解(附源码)
- Spring Cloud限流详解(附源码)
- [Tools]获取域环境内所有用户登录信息(附源码及程序)
- Android中的SharedPreference存储(附源码)
- Python开源软件大全(内附源码)
- 史上最全的Javascript面试题总结(内附答案)
- iOS Cell嵌套UIWebView(内附UIWebView详解)
- 决策树算法详解(内附Python函数)
- JavaScript动画附源码(一)
- 干货:制造业中的机械智能(内附完整PPT)
- UVa 540
- 5.6解题报告
- FPGA固化方法
- 王小草【机器学习】笔记--提升
- react demo7 (设置组件自身属性...this.props)
- JavaScript中的跨域详解(内附源码)
- 2017.5.6 子矩阵 思考记录
- STM32 中JTAG 引脚作为普通IO口设置方法
- vector实现三维数组
- 【BOM】Window对象、事件、方法及DOM与BOM的区别联系
- zoj 3633 rmq或线段树
- bzoj 4069: [Apio2015]巴厘岛的雕塑 (DP)
- 06-图2 Saving James Bond
- 机器学习之贝叶斯网络