解决ajax跨域请求 (总结)

ajax跨域请求,目前已用几种方法实现:

1)用原生js的xhr对象实现。

               var url="http://freegeoip.net/json/";
 
                //创建xhr对象
                function createCORSXhr(url,method){
                     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;                        
                     }
 
                //创建ajax请求,支持跨域
                function sendAjaxRequest(){
                     var xhr=createCORSXhr(url,"get");
                     xhr.onload=function(){
                          if(xhr.readyState==4){
                          if(xhr.status>=200 && xhr.status<300 || xhr.status==304){
                               alert(xhr.responseText);
                               }else{
                                    alert(" ajax error...")
                                    }
                          }
                     };
                     xhr.onerror=function(){
                          alert("error code:"+xhr.status)
                     }
                     xhr.send(null);
                     };

                sendAjaxRequest()

这种方式需要获取相应对象的支持,对于IE,则是XDomainRequest,此种方式cookie不会参与传递。该方式应用了CORS(跨域资源共享)技术,说到底,就是在请求头和响应头中做手脚。在请求头中,加上Origin:协议+域名+端口,当然也可以Origin:null。在响应头中,服务端返回Access-control-Allow-Origin:*.

2),通过jsonp数据来实现,说白了,jsonp就是js可执行文件,由于<script>和<link>,<img>加载的文件不受同源限制,所以可以通过设置src和href来加载相应的跨域json或者xml数据,但是这种方式需要服务端相配合(服务端需要取出请求字符串中的回调函数名,并且返回给客户端)。jsonp的格式为:回调函数名(jsonData)。

     jQuery中的$.getJSON()默认实现了这种方式,只需要在url?callback=?即可,当然也可以手动指定回调函数名。

该种方式一定需要服务端的配合。

测试网站:http://freegeoip.net/json/

3),第三个就是websocket了,当然需要这样的服务器支持。标准的http服务器是不支持webSocket的。Tomcat7.XX支持websocket。

4),

使用window.name来进行跨域

window对象有个name属性,该属性有个特征:即在一个窗口(window)的生命周期内,窗口载入的所有的页面都是共享一个window.name的,每个页面对window.name都有读写的权限,window.name是持久存在一个窗口载入过的所有页面中的,并不会因新页面的载入而进行重置。

比如:有一个页面a.html,它里面有这样的代码:

再看看b.html页面的代码:

a.html页面载入后3秒,跳转到了b.html页面,结果为:

我们看到在b.html页面上成功获取到了它的上一个页面a.html给window.name设置的值。如果在之后所有载入的页面都没对window.name进行修改的话,那么所有这些页面获取到的window.name的值都是a.html页面设置的那个值。当然,如果有需要,其中的任何一个页面都可以对window.name的值进行修改。注意,window.name的值只能是字符串的形式,这个字符串的大小最大能允许2M左右甚至更大的一个容量,具体取决于不同的浏览器,但一般是够用了。

上面的例子中,我们用到的页面a.html和b.html是处于同一个域的,但是即使a.html与b.html处于不同的域中,上述结论同样是适用的,这也正是利用window.name进行跨域的原理。

下面就来看一看具体是怎么样通过window.name来跨域获取数据的。还是举例说明。

比如有一个www.example.com/a.html页面,需要通过a.html页面里的js来获取另一个位于不同域上的页面www.cnblogs.com/data.html里的数据。

data.html页面里的代码很简单,就是给当前的window.name设置一个a.html页面想要得到的数据值。data.html里的代码:

那么在a.html页面中,我们怎么把data.html页面载入进来呢?显然我们不能直接在a.html页面中通过改变window.location来载入data.html页面,因为我们想要即使a.html页面不跳转也能得到data.html里的数据。答案就是在a.html页面中使用一个隐藏的iframe来充当一个中间人角色,由iframe去获取data.html的数据,然后a.html再去得到iframe获取到的数据。

充当中间人的iframe想要获取到data.html的通过window.name设置的数据,只需要把这个iframe的src设为www.cnblogs.com/data.html就行了。然后a.html想要得到iframe所获取到的数据,也就是想要得到iframe的window.name的值,还必须把这个iframe的src设成跟a.html页面同一个域才行,不然根据前面讲的同源策略,a.html是不能访问到iframe里的window.name属性的。这就是整个跨域过程。

看下a.html页面的代码:

上面的代码只是最简单的原理演示代码,你可以对使用js封装上面的过程,比如动态的创建iframe,动态的注册各种事件等等,当然为了安全,获取完数据后,还可以销毁作为代理的iframe。网上也有很多类似的现成代码,有兴趣的可以去找一下。

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

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏yang0range

React Native在Android当中实践(三)——集成到Android项目当中

version字段没有太大意义(除非你要把你的项目发布到npm仓库)。scripts中是用于启动packager服务的命令。dependencies中的reac...

1412
来自专栏IMWeb前端团队

node.js入门心得

很多前端开发的同学应该都会接触或者了解nodejs,但是经常会听到入门难的抱怨。一方面不知道怎么学习nodejs。另一方面,拿到一些大牛写的nodejs源代码,...

2497
来自专栏Python自动化测试

python自动化环境搭建

selenium是测试web应用程序的框架,selenium为没有测试脚本的人提供了(seleniumide)提供了录制/回放的工具,同时它也提供了特定...

1703
来自专栏较真的前端

PWA 入门: 写个非常简单的 PWA 页面

7005
来自专栏SpringBoot 核心技术

第二十五章:SpringBoot添加支持CORS跨域访问

2354
来自专栏用户2442861的专栏

git以及github的使用(1)

http://my.oschina.net/bxxfighting/blog/378196

631
来自专栏SpringBoot 核心技术

第十六章:使用Redis作为SpringBoot项目数据缓存

2462
来自专栏SpringBoot 核心技术

第十二章:SpringBoot使用LogBack作为日志组件

1634
来自专栏nummy

sphinx入门指南【2】 toctree指令详解

reST本身并不支持同时与多个文档进行交互,或者说将一个文档保存到多个文件中。Sphinx提供了自定义指令toctree来支持实现这个功能。

1263
来自专栏世界第一语言是java

mysql官网下载最新版升级版本多版本安装教程

2225

扫码关注云+社区

领取腾讯云代金券