AJAX与AJAX的跨域
一、什么是 AJAX ?
AJAX = 异步 JavaScript 和 XML。AJAX 是一种用于创建快速动态网页的技术。通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。传统的网页(不使用AJAX)如果需要更新内容,必需重载整个网页面。有很多使用 AJAX 的应用程序案例:新浪微博、Google 地图、开心网等等。
总结来说:AJAX就是一种异步局部刷新技术。
二、关于AJAX跨域。
AJAX 的出现使得网页可以通过在后台与服务器进行少量数据交换,实现网页的局部刷新。但是出于安全的考虑,ajax不允许跨域通信。如果尝试从不同的域请求数据,就会出现错误。如果能控制数据驻留的远程服务器并且每个请求都前往同一域,就可以避免这些安全错误。但是,如果仅停留在自己的服务器上,Web 应用程序还有什么用处呢?如果需要从多个第三方服务器收集数据时,又该怎么办?
1、Ajax为什么不能跨域?到底是卡在哪个环节了?(下面项目中具体说,这里先说下结论)。 Ajax其实就是向服务器发送一个GET或POST请求,然后取得服务器响应结果,返回客户端。理论上这是没有任何问题的,然而普通ajax跨域请求,在服务器端不会有任何问题,只是服务端响应数据返回给浏览器的时候,浏览器根据响应头的Access-Control-Allow-Origin字段的值来判断是否有权限获取数据,一般情况下,服务器端如果没有在这个字段做特殊处理的话,跨域是没有权限访问的,所以响应数据被浏览器给拦截了,所以在ajax回调函数里是获取不到数据的(来自园友补充)。所以现在ajax跨域的问题可以转化为数据怎么拿回客户端的问题。
2、既然不能直接访问第三方站点,我们可以在服务器上面做代理,通过ajax向代理发送请求,代理获得数据后在返回给客户端,当然这是一种解决办法,但是一次请求要从客户端经过代理到第三方站点,然后再原路返回,响应速度是个问题。
3、我们发现我们可以将一些js、css等文件放在第三方的服务器上面,如CDN等来加快网页的打开速度,这样是没有任何问题的,也就是说web页面可以加载放在任意站点的js、css、图片等资源,不会受到"跨域"的影响。这个时候,我们会想到:既然我们可以调用第三方站点的js,那么如果我们将数据放到第三方站点的js中不就可以将数据带到客户端了吗?
三、解决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=?即可,当然也可以手动指定回调函数名。该种方式一定需要服务端的配合。
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进行跨域的原理。