通过XHR实现Ajax通信的一个主要限制,来源于跨域安全策略。默认情况下XHR对象只能访问与包含它的页面位于同一个域中的资源,这种安全策略可以预防某些恶意行为。但是,实现合理的跨域请求也是很重要的。
CORS(Cross-Origin Resource Sharing),跨源资源共享,是W3C的一个工作草案,定义了在必须访问跨源资源时,浏览器与服务器该如何沟通。其背后的基本思想是使用自定义的HTTP头部,让浏览器与服务器进行沟通,从而决定请求或响应是应该成功还是应该失败。
比如:一个简单的使用get或者post发送的请求,它没有自定义的头部,在发送该请求时,需要给它附加一个额外的Origin头部,其中包含请求页面的源信息(协议、域名和端口),以便服务器根据这个头部信息来决定是否给予响应。
IE8中引入了XDR(XDomainRequest)类型,这个对象与XHR类似,能够实现安全可靠的跨域通信。
XDR与XHR不同之处在于:
1. cookie不会岁请求发送,也不会随响应返回。
2. 智能设置请求头部信息中的 Content-Type字段
3. 不能访问响应头部信息
4. 只支持get和post请求
XDR使得CSRF(跨站点请求伪造)和XSS(跨站点脚本)的问题得到缓解。
XDR的使用与XHR相似。
1、创建XDR对象;
2、调用open()方法,这里open方法只有两个参数,因为所有XDR请求都是异步执行的;
3、调用send()方法。
在接收到响应后,只能访问响应的原始文本,没有办法确定响应的状态码。要检测错误,可以指定一个onerror事件处理程序
var xdr = new XDomainRequest();
xdr.onload = function () {
alert(xdr.responseText);
};
xdr.onerror = function () { //错误处理程序
alert("An error occurred.");
};
xdr.open("post","http://www.somewhert-else.com/page/");
xdr.contentType = "application/x-www-form-urlencoded";
xdr.send("name1=value1&name2=value2");
注:由于导致XDR请求失败的因素有很多,因此不要忘记通过onerror事件处理程序来捕获该事件
XDR与XHR一样,也支持timeout属性及ontimeout事件处理程序
Firefox3.5+/Safari4+/Chrome/iOS版Safari和Android平台中的WebKit都通过XMLHttpRequest对象实现了对CORS的原生支持。要请求位于另一个域中的资源,使用标准的XHR对象并在open()方法中传入绝对URL即可
与XDR不同,通过跨域XHR对象可以访问status和statusText属性,而且支持同步请求。其主要限制有:
1、不能使用setRequestHeader()设置头部信息
2、不能发送和接收cookie
3、调用getAllResponseHeaders()方法总会返回空字符串
Tips:对于本地资源,最好使用相对URL,对于远程资源再使用绝对URL
检测XHR是否支持CORS的最简单的方式,就是检查是否存在withCredentials 属性。在结合检测XDomainRequest对象是否存在,就可以兼顾所有浏览器了。
function createCORSRequest (method,url) {
var xhr = createXHR();
if ("withCredentails" in xhr) {
xhr.open(method,url,true);
} else if (typeof XDomainRequest != "undefined") {
xhr = new XDomainRequest();
xhr.open(method,url);
} else {
xhr = null;
}
return xhr;
}
var request = createCORSRequest("get","http://www.somewhere-else.com");
if(request) {
request.onload = function (){
//相关代码
}
request.send();
}
一个网页可以从任何网页中加载图像,不用担心跨域不跨域。图像Ping是与服务器进行简单/单向的跨域通信的一种方式。请求的数据是通过查询字符串的方式发送的。图像Ping最常用于跟踪用户点击页面或动态广告曝光次数。
其主要缺点有:1、只能发送get请求;2、无法访问服务器响应文本
var img = new Image();
img.onload = function () {
alert("Done!");
};
img.onerror = function () {
alert("Wrong!");
};
img.src = "http://www.example.com/test?name=Jay";
JSONP是JSON with padding(填充式JSON/参数式JSON)的简写,是包含在函数调用中的JSON。
JSONP由两部分组成:回调函数和数据
回调函数是当响应到来时应该在页面中调用的函数。回调函数的名字一般是在请求中指定的,而数据就是传入回调函数中的JSON数据。
JSONP是通过动态script元素来使用的,使用时可以为src属性指定一个跨域的URL。
优点:能够直接访问响应文本,支持在浏览器与服务器之间的双向通信
缺点:1、JSONP是从其他域加载代码执行,若其他域不安全,很可能会在响应中夹杂恶意代码;2、确定JSONP请求是否失败并不容易
<html>
<head>
<meta charset="utf-8"/>
<title>JSONP跨域请求title>
head>
<body>
<div id="box">div>
<script type="text/javascript">
function handle (response) { //回调函数,response就是响应数据
var box = document.getElementById("box");
var html = "";
html += "响应数据为:" + response.words;
box.innerHTML = html;
console.log(html);
}
function jsonp (url,callback) {
var script = document.createElement("script");//动态创建script
script.src = url;
var header = document.getElementsByTagName("head")[0];
header.appendChild(script);
}
jsonp("data.json",handle);
script>
body>
html>
data.json
handle(
{
"words":"hello JSONP"
}
)
注:一定要注意,JSONP是在函数调用里的JSON
Ajax是一种从页面向服务器请求数据的技术,而Comet是一种服务器向页面推送数据的技术。Comet能够让信息近乎实时的被推送到页面上,非常适合处理体育比赛的分数和股票报价。
有两种实现Comet的方式:长轮询和流。
长轮询是短轮询的一个翻版,即浏览器定时向服务器发送请求,看有没有更新的数据。页面发起一个到服务器的请求,然后服务器一直保持连接打开,直到有数据可发送。发送完数据之后,浏览器关闭连接,接着又发起一个到服务器的新请求。这一过程在页面打开期间一直持续不断。
长轮询(long polling)模式涉及了打开连接的技术。连接由服务器端保持着打开的状态,只要一有事件发生,响应就会被提交,然后连接关闭。接下来。一个新的长轮询连接就会被正在等待新事件到达的客户端重新打开。
浏览器向服务器发送一个请求,而服务器保持连接打开,然后周期性的向浏览器发送数据。
使用XHR对象实现HTTP流:
/*=====================使用XHT对象实现HTTP流=======================*/
function createStreamingClient (url,progress,finished) {
var xhr = new XMLHttpRequest();
var received = 0;
xhr.open("get",url,true);
xhr.onreadystatechange = function () {
var result;
if (xhr.readyState == 3) {
//只取得最近数据并调整计数器
result = xhr.responseText.substring(received);
received += result.length;
//调用progress函数
progress(result);
} else if (xhr.readyState == 4) {
finished(xhr.responseText);
}
}
xhr.send(null);
return xhr;
}
var client = createStreamingClient("s.php",function(data){
alert("Received" + data);
},function (data) {
alert("Done!")
});
SSE是围绕只读Comet交互推出的API,用于创建到服务器的单向连接,服务器通过这个连接可以发送任意数量的数据。
首先,要创建一个新的EventSource对象,并传入一个入口点,传入的URL必须与原页面同源。EventSource的实例有一个readyState属性,值为0表示正连接到服务器,1为表示打开了连接,2为表示关闭了连接。
其目标是在一个单独的持久连接上提供全双工/双向通信。
在JavaScript中创建了Web Sockets之后,会有一个HTTP请求发送到服务器以发起连接,在取得服务器响应后,建立的连接会使用HTTP升级从HTTP协议交换为Web Socket 协议。
使用自定义协议的好处是:能够在客户端和服务器之间发送非常少量的数据,而不必担心HTTP那样字节级的开销。
1、实例WebSocket对象,并传入URL
var socket = new WebSocket("ws://www.example.com/server.php");//必须传入绝对URL
实例化WebSocket对象后,浏览器会马上尝试创建连接。
2、发送和接收数据
socket.send("hello");
var message ={
time: new Date(),
text:"hello world"
}
socket.send(JSON.stringify(message));//WebSocket只能通过连接发送纯文本数据,因此将数据序列化为JSON字符串