ajax可以实现异步和同步,但是无法跨域访问资源。
主要的跨域访问有CORS,jsonp,comet,websocket等。
先说说什么是跨域:对于资源的访问,只要是来自不同协议(http,https..)或者不同域名(www.xx.com,www.yy.com,或者是域名对应的ip地址,或者是网站的子域)或者不同的端口号都是跨域访问。
处于安全因素的考虑,跨域一半都是不被允许的。因为如果有人可以随意访问你服务器上的资源,那么。。。0 0。。。。
1.CORS(cross-origin resource sharing)
主要实现的方法是在请求的头部加上Origin,包含请求页面的源信息(域名,协议,端口)。然后服务器根据这个信息判断是否要进行相应,如果要的话,就在response的头部加上Access-Control-Allow-Origin:请求页面的源信息。如果不加,或者不匹配,浏览器就驳回这个请求。注意这时请求和相应都是不包含cookie信息的。
2.JSONP,图片Ping
据说在CORS出现之前,常用JSONP和Ping进行跨域的资源访问,两者的访问原理都相同,使用页面中可以进行跨域访问资源的标签进行资源的获取。
JSONP:
由于<script>标签是可以跨域加载资源的,所以在该标签的src上加上访问的内容和回调函数,当请求的信息加载到页面之后,就可以通过本地的callback函数对数据进行处理了。(当把多个js文件加载到一个页面下的时候,这些js就是共享的了,互相可以访问)。
<span style="font-size:18px;color:#333333;">function a(){
console.log("1111");
}</span>
a是callback函数,想要在请求结束之后调用callback函数,服务器要在返回的数据中添加a函数调用的文本。
在页面中添加请求:
<span style="font-size:18px;color:#333333;"><script type="text/javascript" src="http://localhost:3000/jsonp?callback=a"></script></span>
如下是用express搭建的服务器:
<span style="font-size:18px;color:#333333;">router.get('/jsonp',function(req, res, next) {
// console.log(req);
var ques = req.query;
res.send("console.log('GET啦');"+ques.callback+"();");
});</span>
表示在接受到这么一个路径下的访问的时候,返回send中的信息(这些文本都是js代码)
于是在加载成功之后看控制台:
表示成功运行了script标签返回的js代码
优点:可以访问返回的信息
缺点:不够安全,不好确定请求是否成功,只能用get方法.
虽然H5中增加了onerror方法,但是貌似支持还不是很好。。
Ping:
和jsonp的原理一样,图像可以跨域加载,所以可以这样:
<span style="font-size:18px;color:#333333;">var img = new Image();
img.onload = function(){
console.log("finished");
};
img.src="http://xx.com:8080/test?name=query"</span>
在指定了img的src之后,就对相应的地址发送了包含name的一个请求。
缺点:不能访问服务器返回的信息。。 ,只能用get方法
2.5 document.domain, window.name
这个主要是不同iframe之间的通信。比如说两个frame之间是不同域的,但是主域相同,就可以通过修改document.domain来进行域名的提升(只能设置成自身或者更高一级的父域)。这样就可以进行同源访问了。
window.name是这个窗口中所有历史页面都可以访问的属性,并且每个页面对于这个属性都有读写权,可以通过把数据放在window.name来进行交互。
3.comet
以上还是跨域资源方面的请求,从comet开始应该算是web间的通信了吧。comet是服务器向页面推送数数据的技术
comet主要通过长轮询和http流实现通信。
3.1长轮询
短轮训是每请求一个资源,就发送一次http的请求。而长轮询是客户端向服务器发起请求后,服务器就挂起了这个请求,不回应客户端,这样这个http的请求就一直开启,直到服务器发现有消息需要推送了,就拿着消息响应客户端,然后客户端收到消息之后马上再发送新的一个http请求,以此来保持联系。
3.2http流
http流在整个页面的生命周期中只有一次http请求,服务器周期性地像客户端推送消息,并且不关闭连接。而客户端可以通过XHR的readyState来获取消息。因为对于readyState,0表示没有初始化,1表示建立连接,但没发送,2表示已发送,正在处理,3表示正在处理,4表示响应完成。
所以监听readyState,当它为3的时候,就通过游标来获得新得到的数据:
<span style="font-size:18px;color:#333333;">var xhr = new XMLHttpRequest(),
receive = 0; //游标
xhr.open("get",url,true);
xhr.onreadystatechange = function(){
var ret;
if(xhr.readystate == 3){
ret = xhr.responseText.substring(receive);
receive +=ret.length;
callback(ret);
}else if(xhr.readystate == 4){
Finished();
}
xhr.send(null);
return xhr;
}</span>
3.3 SSE
Server-Sent Events,是支持comet的api。
通过:
<span style="font-size:18px;color:#333333;">var source = new EventSource(url); //url需要和页面同源的
</span>
开启连接,sse支持长轮询和http流,在连接断开的时候回自动再连接。如果不想再连接了,可以通过source.close()关闭连接。
source有三个事件,open,message,error分别在建立连接,从服务器接受新事件,出错的时候触发。
4.websocket
听说有通过websocket制定的分屏应用,感觉好有趣=w=,希望什么时候能试试
websocket协议是在http的基础上定制的协议,虽然有http的头部,但是之后貌似和http就没有关系了。未加密的协议是ws://,加密的协议是wss://
websocket比较方便,但是对于服务器的要求高,因为服务器需要支持websocket。
它没有同源策略的限制,是否通信只取决于服务器。有三个事件:open,error,close。由于不支持dom2级事件,所以要用dom0级来绑定事件。