js中的跨域请求应该也算是一个重点,具体什么叫跨域,在这里我就不展开了,能够查一下浏览器的同源策略和跨域的定义。原来只知道经常使用的jsonp和document.domain这两种方式,这几天学习了一下其余几种跨域请求的方式,正好一块儿作个总结。javascript
jsonp请求应该是你们最为熟悉的一种(至少是我知道的第一种跨域请求方式)。jsonp的原理是利用<script>标签的跨域特性,能够不受限制地从其余域中加载资源,相似的标签还有<img>.利用<script>标签的这个特性能够从服务器中返回须要的跨域数据。下面用代码的小例子加以分析:
例子中html文件和后台php(这里我以php后台为例,后台我本身会的是php)文件位于不一样域中!php
先看html文件:
文件底部的<script>标签的src连接到后台service.php文件,并传入参数callback,这里的关键是把回调函数做为参数传给后台。html
再看后台php文件:html5
文件接收回调函数并把要返回的参数以参数注入的方式注入到回调函数中,再返回给客户端。
这样的话浏览器解析script标签,并执行返回的js文档,此时服务器返回的数据做为参数,传到页面中定义好的 jsonpBack 函数里.(动态执行回调函数),就拿到了咱们须要的跨域数据。java
这里补充一点就是jquery对jsonp有着很好的支持,jquery中$.getJSON方法将jsonp的调用方式进行了封装,用起来十分方便,使用的方式以下便可:jquery
<script> $.getJSON("后台文件地址?参数=**",function(jsondata){ //在这里就能够操做从后台拿到的jsondata数据 }) </script>
这种方式用在主域名相同子域名不一样的跨域访问中,举个例子:http://a.frame.com和http://b.frame.com 他们的主域名都是frame.com 这两个域名中的文件能够用这种方式进行访问,经过在两个域中具体的文件中设置document.domain="frame.com"就可达到跨域访问的目的。web
实际应用中经常用在iframe中窗口之间的访问,根据浏览器的同源策略,浏览器中不一样域的框架之间是不能进行js的交互操做的,因此一个窗口是不能拿到另外一个窗口中的contentWindow对象的属性和方法的(注意是能拿到contentWindow对象的,只是属性和方法都不可用)。为了能拿到数据,只要在两个iframe中分别写入document.domain="主域名",这样设置以后,就能拿到contentWindow对象的属性和方法了。代码就这么简单的一行,我就不写小例子了。json
window的name属性有个特征:在一个窗口(window)的生命周期内,窗口载入的全部的页面都是共享一个window.name的,每一个页面对window.name都有读写的权限,window.name是持久存在一个窗口载入过的全部页面中的,并不会因新页面的载入而进行重置。跨域
这是什么意思呢?通俗来说,就是好比我在a.html这个页面中设置了window.name="a";而后让window从新加载b.html页面,而后在b.html页面中输出window.name会发现window.name=“a”。因此就算a.html和b.html这两个页面不是在同一个域中的,也能够在b页面中拿到a页面设置的window.name的值,跨域的核心思路就是这个原理。浏览器
实际应用中也是经常用在两个iframe之间(须要结合iframe的特性来用),先上一张从别人那边借鉴过来的原理图,我再按照本身的理解进行分析:
图中有三个页面,getDomainData.html是获取数据的页面,null.html是一个和getDomainData.html同域的空页面,它的做用是做为一个中转站,进行数据的过渡。data.html是要获取数据的所在页面,这里有着咱们要的数据,它和getDomainData.html处于不一样域中,因此取数据是跨域访问。具体的过程是这样的:在getDomainData.html中创建一个子页面iframe,把这个iframe的src指向b.com/data.html,这样当这个iframe加载完成后就能够访问到data.html中的window.name的数据,以后再将iframe的src改成a.com/null.html,跳回getDomainData.html的同一个域,这样根据同源策略,getDomainData.html就能够访问到null.html中取得的data.html的数据了。获取数据之后最好销毁这个iframe,释放掉内存,也保证了安全。下面附上代码小例子:
getDomainData.html:
<script type="text/javascript"> var flag=0; var data; var iframe=document.createElement("iframe");//建立一个中转站iframe document.appendChild(iframe); getData=function(){//iframe加载完成后调用的处理函数 if(flag==1){ data=iframe.contentWindow.name;//读取b.html中的window.name }else{ flag=1; iframe.src="http://a.com/null.html";//跳回getDomainData.html的同一个域 } }; iframe.src="http://b.com/data.html";//设置src到要得到数据的域中的对应页面 if (iframe.attachEvent) {//兼容IE,监听iframe加载完成 iframe.attachEvent('onload', getData); } else { iframe.addEventListener('load',getData); } </script>
data.html:
<script> window.name="被获取数据"//简单的一行代码 </script>
最后的iframe销毁:
<script> iframe.contentWindow.document.write("");//状况iframe中的内容 iframe.contentWindow.close();//避免iframe的内存泄漏 document.body.removeChild(iframe);//移除iframe节点 </script>
window.postMessages是html5中实现跨域访问的一种新方式,可使用它来向其它的window对象发送消息,不管这个window对象是属于同源或不一样源。
该方式的使用仍是十分简单的,给要发送数据的页面中的window对象调用一个postMessage(message,targetOrigin)方法便可,该方法的第一个参数message为要发送的消息,类型只能为字符串;第二个参数targetOrigin用来限定接收消息的那个window对象所在的域,若是不想限定域,直接使用通配符 * 。再让接收数据页面的window对象监听自身的message事件来获取传过来的消息,消息内容储存在该事件对象的data属性中。简单的小例子以下:
test.html(发送页面):
<script> <iframe name="receive" id="iframe" src="test2.html" scrolling="no"> </iframe> <script type="text/javascript"> window.onload=function(){ var iframWindow = document.getElementById("iframe").contentWindow; iframWindow.postMessage("A secret", "*");//发送消息 } </script>
test2.html(接收页面)
<script> window.addEventListener("message",function(e){ alert(e.data);//接收到的消息 }) </script>
测试结果以下
关于这个用法困扰了我很久,困扰1:由于最后弹出的消息是在test.html,而不是在test2.html中,我不肯定是由于test.html包含了test2.html,因此浏览器渲染才弹出的alert,仍是test2.html接收到消息的反馈。后来查阅了权威的文档,才有了进一步的理解,应该是test2.html收到消息,以iframe在test.html中渲染加载出的。
困扰2:postMessage的调用对象是目标窗口仍是发送窗口,是否能以window形式调用?
查阅文档后得出结论:*postMessage的调用对象,是其余窗口的一个引用,即目标窗口,不是要发送的窗口,(这里比较出乎意料) 并且postMessage想要通讯必须使得一个窗口以iframe的形式存在于另外一个窗口,或者一个窗口是从另外一个窗口经过window.open()或者超连接的形式打开的(一样能够用window.opener获取源窗口);换句话说,你要交换数据,必须能获取目标窗口(target window)的引用,否则两个窗口之间毫无联系,想通讯也无能为力,因此不能直接以主页面window的形式调用。
具体的权威解释请看这个连接: window.postMessage
CORS(Corss-Origin-Resource Sharing,跨源资源共享),是一种网络浏览器的技术规范,它为Web服务器定义了一种方式,容许网页从不一样的域访问其资源,而这种访问是被同源策略所禁止的。CORS系统定义了一种浏览器和服务器交互的方式来肯定是否容许跨域请求。 它是一个妥协,有更大的灵活性,但比起简单地容许全部这些的要求来讲更加安全。
CORS背后的基本思想,就是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功仍是应该失败。
CORS的使用仍是十分简便的,好比一个简单的GET或者POST请求,在发送的时候给它附加一个额外的origin头部,其中包含请求页面的源信息(协议、域名和端口),以便服务器根据这个头部信息来决定是否给以响应。下面是javascript高级程序设计书上的一个小例子:
Origin:http://www.nczonline.net
若是服务器认为这个请求能够接受,就在Access-Control-Allow-Origin头部中回发相同的源消息(若是是公共资源,能够回发“ * ”)。例如:
Access-Control-Allow-Origin:http://www.nczonline.net
这样设置以后,服务器与浏览器就能够进行跨域信息的交换了。具体的在不一样浏览器上的支持和使用,我就不展开了,js高级程序设计书上提到了不少,网上查一下也有不少。
Web Sockets是一种新浏览器API,能在一个单独的持久链接上提供全双工、双向通讯,使用ws(代替http://)或wss(代替https://)协议,可用于任意的客户端和服务器程序。
web sockets原理:在JS建立了web socket以后,会有一个HTTP请求发送到浏览器以发起链接。取得服务器响应后,创建的链接会使用HTTP升级从HTTP协议交换为web sockt协议。
使用的小例子:
// 建立一个Socket实例 var socket = new WebSocket('ws://www.example.com/server.php'); // 打开Socket socket.onopen = function(event) { // 发送消息 socket.send('a secret'); // 监听消息的接收 socket.onmessage = function(event) { var data=event.data; //处理data... }; // 监听socket的关闭 socket.onclose = function(event) { console.log('socket has closed',event); }; // 关闭Socket //socket.close() };
一样附上权威文档供参考:Web Workers API
除此以外还有一些跨域访问的方式:好比Comet、图像Ping、SSE等,感兴趣的能够直接查找这些内容。在这些跨域访问方式上,各有各的适用访问和相应的限制,须要结合实际来适用。我在这里有个疑问:我本身运用的比较多的就是jsonp这种方式,那么在实际开发中,比较推崇的跨域访问方式是哪一种呢?还有就是html5的postMessage是否是能够取代window.name(一样都须要一个iframe做为中间媒介)这类访问方式,这个新API方式是否是在实际中颇有效呢?但愿有经验的大牛能够解答,不胜感激。