Ajax与Comet
Ajax(Asynchronous JavaScript + XML的简写)可以向服务器请求数据而无需卸载(刷新)页面,带来更好的用户体验。 一、XMLHttpRequest对象/* 兼容IE早期版本 */
function createXHR(){
if (typeof XMLHttpRequest != "undefined"){
return new XMLHttpRequest();
} else if (typeof ActiveXObject != "undefined"){ // 适用于IE7之前的版本
if (typeof arguments.callee.activeXString != "string"){
var versions = ["MSXML2.XMLHttp.6.0","MSXML2.XMLHttp.3.0","MSXML2.XMLHttp"],i,len;
for (i=0,len=versions.length; i < len; i++){
try {
new ActiveXObject(versions[i]);
arguments.callee.activeXString = versions[i];
break;
} catch (ex){
//skip
}
}
}
return new ActiveXObject(arguments.callee.activeXString);
} else { // XHR对象和ActiveX对象都不存在,则抛出错误
throw new Error("No XHR object available.");
}
}
1. XHR的用法xhr.open("请求的类型get|post等","请求的URL","是否异步发送请求");
说明: xhr.send("请求主体发送的数据");
说明: 补充:xhr.open()方法为“false”,即同步请求,JavaScript代码会等到服务器响应后再继续执行;否则,继续执行后续代码。 在收到服务器响应后,相应的数据会自动填充XHR对象的属性。
// 为确保接收到适当的响应 200:成功;304:资源未被修改
if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
console.log(xhr.responseText);
}
说明: 对于异步请求,可以检测XHR对象的readyState属性,该属性表示请求/响应过程的当前活动阶段
readyState属性的值发生变化,都会触发readystatechange事件。可以利用这个事件来检测每次状态变化后readyState的值。不过,必须在调用open()之前指定onreadystatechange事件处理程序才能确保跨浏览器兼容性。 var xhr = createXHR();
xhr.onreadystatechange = function(event){
// 不要使用this,作用域会产生问题,在部分浏览器中会执行失败
if (xhr.readyState == 4){
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
console.log(xhr.responseText);
} else {
console.log("Request was unsuccessful: " + xhr.status);
}
}
};
xhr.open("get","example.txt",true);
xhr.send(null);
在接收到响应数据之前可以调用abort()方法来取消异步请求: xhr.abort();
xhr = null; // 解除引用,释放内存
2. HTTP头部信息setRequestHeader():设置自定义的请求头信息。必须在调用open()方法之后且调用send()方法之前调用。 var xhr = createXHR();
xhr.onreadystatechange = function(){};
xhr.open("get","example.php",true);
xhr.setRequestHeader("MyHeader","MyValue");
xhr.send(null);
3. GET请求open()方法的URL尾部的查询字符串必须经过正确的编码 function addURLParam(url,name,value) {
url += (url.indexOf("?") == -1 ? "?" : "&");
url += encodeURIComponent(name) + "=" + encodeURIComponent(value);
return url;
}
var url = "http://test.com";
url = addURLParam(url,"uid",5);
url = addURLParam(url,"siteid",123); // "http://test.com?uid=5&siteid=123"
xhr.open("get",url,true);
xhr.send(null);
4. POST请求POST请求将数据作为请求的主体 /* 序列化表单 */
function serialize(form){
var parts = new Array();
var field = null;
for (var i=0,len=form.elements.length; i < len; i++){
field = form.elements[i];
switch(field.type){
case "select-one":
case "select-multiple":
for (var j=0,optLen = field.options.length; j < optLen; j++){
var option = field.options[j];
if (option.selected){
var optValue = "";
if (option.hasAttribute){
optValue = (option.hasAttribute("value") ?
option.value : option.text);
} else {
optValue = (option.attributes["value"].specified ?
option.value : option.text);
}
parts.push(encodeURIComponent(field.name) + "=" +
encodeURIComponent(optValue));
}
}
break;
case undefined: //fieldset
case "file": //file input
case "submit": //submit button
case "reset": //reset button
case "button": //custom button
break;
case "radio": //radio button
case "checkbox": //checkbox
if (!field.checked){
break;
}
/* falls through */
default:
parts.push(encodeURIComponent(field.name) + "=" +
encodeURIComponent(field.value));
}
}
return parts.join("&");
}
/* 发送请求 */
function submitData(){
var xhr = createXHR();
xhr.onreadystatechange = function(event){
if (xhr.readyState == 4){
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
alert(xhr.responseText);
} else {
alert("Request was unsuccessful: " + xhr.status);
}
}
};
xhr.open("post","postexample.php",true);
// 表单提交的内容类型
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
var form = document.getElementById("user-info");
// 请求主体为数据
xhr.send(serialize(form));
}
二、XMLHttpRequest 2级XMLHttpRequest 1级只是把已有的XHR对象的实现细节描述了出来。而XMLHttpRequest 2级则进一步发展了XHR。并非所有浏览器都完整地实现了XMLHttpRequest 2级规范,但所有浏览器都实现了它规定的部分内容。 1. FormData// 创建FormData对象
var data = new FormData();
data.append("name","ligang");
// 用表单元素填充
xhr.open("post",true);
var form = document.getElementById("user-info");
// 使用FormData的方便之处在于不必明确地在XHR对象上设置请求头。
// xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
xhr.send(new FormData(form));
2. 超时设定IE8为XHR对象添加了一个timeout属性,表示请求在等待响应多少毫秒后就终止。 xhr.open("get","timeout.php",true);
xhr.timeout = 60 * 1000;
xhr.ontimeout = function(){
alert("Request did not return in a second.");
};
xhr.send(null);
对于其他浏览器的兼容做法 xhr.open("get",true);
xhr.onreadystatechange = function(event){
if (xhr.readyState == 4){
// 清除定时器
clearTimeout(timeout);
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
console.log(xhr.responseText);
} else {
console.log("Request was unsuccessful: " + xhr.status);
}
}
};
// 设置超时时间 1分钟
var timeout = setTimeout(function() {
xmlHttpRequest.abort();
xmlHttpRequest = null;
},60 * 1000);
xmlHttpRequest.send(null);
3. overrideMimeType()方法重写XHR响应的MIME类型,必须在send()方法之前。 如果,服务器返回的MIME类型是text/plain,但数据中实际包含的是XML。根据MIME类型,responseXML属性中仍然是null。此时,通过overrideMimeType()方法,可以保证把响应当作XML而非纯文本来处理(即,responseXML中被赋值)。 var xhr = createXHR();
xhr.open("get","text.php",true);
xhr.overrideMimeType("text/xml");
xhr.send(null);
三、进度事件6个进度事件:
1. load事件可以代替readystatechagne事件。其处理程序会接收到一个event对象,其target属性指向XHR对象实例,因而可以访问到XHR对象的所有方法和属性。然而,并非所有浏览器都实现了事件对象。 2. progress事件其处理程序会接收一个event对象,其target属性指向XHR对象实例,但包含着三个额外的属性
var xhr = createXHR();
xhr.onload = function(event){
// event.target存在兼容性问题,所以只能使用xhr
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
console.log(xhr.responseText);
} else {
console.log("Request was unsuccessful: " + xhr.status);
}
};
xhr.onprogress = function(event){
var divStatus = document.getElementById("status");
if (event.lengthComputable){
divStatus.innerHTML = "Received " + event.position + " of " + event.totalSize + " bytes";
}
};
xhr.open("get","altevents.php",true);
xhr.send(null);
四、跨源资源共享CORS(Cross-Origin Resource Sharing)背后的基本思想,就是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功还是失败。 在发送请求时,给其附加一个额外的Origin头部,其中包含请求页面的源信息(协议、域名和端口),以便服务器根据这个头部信息来决定是否给予响应。 Origin: http://www.test.com
如果服务认为这个请求可以接受,在Access-Control-Allow-Origin头部中回发相同的源信息(如果是公共资源,可以回发”*”)。 Access-Control-Allow-Origin: http://www.test.com
注意:请求和响应都不包含cookie信息。 1. IE中实现CORS:XDR(XDomainRequest),所有的XDR请求都是异步的,不能创建同步请求。其使用方法类似于XHR。2. 其他浏览器对CORS的实现:通过XMLHttpRequest对象实现对CORS的原生支持。只需给open()方法传入绝对地址。支持同步请求。跨域XHR对象的安全限制: 建议:访问本地资源,最好使用相对URL;访问远程资源,使用绝对URL。 3. 跨浏览器的CORSfunction createCORSRequest(method,url){
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr){ // 检测XHR是否支持CORS的简单方式,就是检测是否存在withCredentials属性
xhr.open(method,true);
} else if (typeof XDomainRequest != "undefined"){ // IE XDR
xhr = new XDomainRequest();
xhr.open(method,url);
} else {
xhr = null;
}
return xhr;
}
var request = createCORSRequest("get","http://www.somewhere-else.com/xdr.php");
if (request){
request.onload = function(){
//do something with request.responseText
};
request.send();
}
五、其他跨域技术利用DOM中能够执行跨域请求的功能,在不依赖XHR对象的情况下也能发送某种请求,其不需要修改服务器端代码。 1. 图像Ping
var img = new Image();
img.onload = img.error = function() {
console.log("Done!");
};
img.src = "http://www.test.com/getImage?id=1";
缺点: 2. JSONP(JSON with padding)两部分组成:回调函数和数据。 function handleResponse(response){
alert("You're at IP address " + response.ip + ",which is in " + response.city + "," + response.region_name);
}
var script = document.createElement("script");
script.src = "http://freegeoip.net/json/?callback=handleResponse";
document.body.insertBefore(script,document.body.firstChild);
优点:能够直接访问响应文本,支持在浏览器与服务器之间双向通信。 3. Comet更高级的Ajax技术,服务器向页面推送数据。 (2)HTTP流:生命周期内只使用一个HTTP连接。浏览器向服务器发送一个请求,而服务器保持连接打开,然后周期性地向浏览器发送数据。 /** * progress:接收数据时调用的函数 * finished:关闭连接时调用的函数 */
function createStreamingClient(url,progress,finished){
var xhr = new XMLHttpRequest(),received = 0;
xhr.open("get",true);
xhr.onreadystatechange = function(){
var result;
if (xhr.readyState == 3){
//get only the new data and adjust counter
result = xhr.responseText.substring(received);
received += result.length;
//call the progress callback
progress(result);
} else if (xhr.readyState == 4){
finished(xhr.responseText);
}
};
xhr.send(null);
return xhr;
}
var client = createStreamingClient("streaming.php",function(data){alert("Received: " + data);},function(data){alert("Done!");});
服务器发送事件:SSE和事件流 4. Web Sockets目标是在一个单独的持久连接上提供全双工、双向通信。 // 必须给WebSocket构造函数传入绝对URL
var socket = new WebSocket("ws://www.example.com/server.php");
// 向服务器发送数据(只能发送纯文本,其他数据需要序列化)
socket.send("Hello");
// 接收服务器的响应数据
socket.onmessage = function(event) {
var data = event.data;
};
其他事件:
注意:WebSocket对象不支持DOM 2级事件侦听器,必须使用DOM 0级语法分别定义各个事件。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |