第21 Ajax 与 Comet
1. XMLHttpRequest对象
创建XHR对象
function createXHR(){
if (typeof XMLHttpRequest != "undefined"){
return new XMLHttpRequest();
} else if (typeof ActiveXObject != "undefined"){
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){
//跳过
}
}
}
return new ActiveXObject(arguments.callee.activeXString);
} else {
throw new Error("No XHR object available.");
}
}
var xhr = createXHR();
(1) XHR的用法
open()方法:
接受 3 个参数:要发送的请求的类型("get"、"post"等)、请求的 URL 和表示是否异步发送请求的布尔值。
xhr.open("get", "example.php", false);
send()方法:
发送特定的请求,send()方法接收
一个参数
,即要作为请求主体发送的数据。如果不需要通过请求主体发送 数据,则必须传入 null,因为这个参数对有些浏览器来说是必需的。调用 send()之后,请求就会被分 派到服务器。
xhr.open("get", "example.txt", false);
xhr.send(null);
XHR 对象的属性:
在收到响应后,响应 的数据会自动填充 XHR 对象的属性
- responseText:作为响应主体被返回的文本。
- responseXML:如果响应的内容类型是"text/xml"或"application/xml",这个属性中将保
存包含着响应数据的 XML DOM 文档。- status:响应的 HTTP 状态。
- statusText:HTTP 状态的说明。
- readyState: 表示请求 /响应过程的当前活动阶段。
- 0:未初始化。尚未调用 open()方法。
- 1:启动。已经调用 open()方法,但尚未调用 send()方法。
- 2:发送。已经调用 send()方法,但尚未接收到响应。
- 3:接收。已经接收到部分响应数据。
- 4:完成。已经接收到全部响应数据,而且已经可以在客户端使用了。
readyState 属性的值由一个值变成另一个值,都会触发一次 readystatechange 事件。
var xhr = createXHR();
xhr.onreadystatechange = function(){
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("get", "example.txt", true);
xhr.send(null);
abort()方法:
调用这个方法后,XHR 对象会停止触发事件,而且也不再允许访问任何与响应有关的对象属性。在 终止请求之后,还应该对 XHR 对象进行解引用操作。由于内存原因,不建议重用 XHR 对象。
(2) HTTP头部信息
- Accept:浏览器能够处理的内容类型。
- Accept-Charset:浏览器能够显示的字符集。
- Accept-Encoding:浏览器能够处理的压缩编码。
- Accept-Language:浏览器当前设置的语言。
- Connection:浏览器与服务器之间连接的类型。
- Cookie:当前页面设置的任何 Cookie。
- Host:发出请求的页面所在的域 。
- Referer:发出请求的页面的 URI。注意,HTTP 规范将这个头部字段拼写错了,而为保证与规范一致,也只能将错就错了。(这个英文单词的正确拼法应该是 referrer。)
- User-Agent:浏览器的用户代理字符串。
setRequestHeader()方法:
设置自定义的请求头部信息。
这个方法接受两个参数
:头部字段 的名称和头部字段的值。要成功发送请求头部信息,必须在调用 open()方法之后且调用 send()方法 之前调用 setRequestHeader()
getResponseHeader()方法:
传入头部字段名称,可以取得相应的响应头部信息。
getAllResponseHeaders()方法
可以取得一个包含所有头部信息的长字符串。
(3) GET请求
可以将查询字符串参数追加 到 URL 的末尾,以便将信息发送给服务器。对 XHR 而言,位于传入 open()方法的 URL 末尾的查询字 符串必须经过正确的编码才行。
xhr.open("get", "example.php?name1=value1&name2=value2", true);
function addURLParam(url, name, value) {
url += (url.indexOf("?") == -1 ? "?" : "&");
url += encodeURIComponent(name) + "=" + encodeURIComponent(value);
return url;
}
var url = "example.php";
//添加参数
url = addURLParam(url, "name", "Nicholas");
url = addURLParam(url, "book", "Professional JavaScript");
//初始化请求
xhr.open("get", url, false);
(4) POST请求
用于向服务器发送应该被保存的数据,向 send()方法中传入某些数据。
2. XMLHttpRequest 2 级
(1) FormData
FormData 为序列化表单以及创建与表单格式相同的数据(用于通过 XHR 传输)提供 了便利。
var data = new FormData();
data.append("name", "Nicholas");
append()方法接收两个参数:键和值,分别对应表单字段的名字和字段中包含的值。可以像 这样添加任意多个键值对儿。而通过向 FormData 构造函数中传入表单元素,也可以用表单元素的数据 预先向其中填入键值对儿:
var data = new FormData(document.forms[0]);
(2) 超时设定
XHR 对象添加了一个
timeout 属性
,表示请求在等待响应多少毫秒之后就终止。在给 timeout 设置一个数值后,如果在规定的时间内浏览器还没有接收到响应,那么就会触发 timeout 事 件,进而会调用 ontimeout 事件处理程序。
(3) overrideMimeType()方法
用于重写 XHR 响应的 MIME 类型。
3. 进度操作
6 个进度事件:
(1) loadstart:在接收到响应数据的第一个字节时触发。
(2) progress:在接收响应期间持续不断地触发。
(3) error:在请求发生错误时触发。
(4) abort:在因为调用 abort()方法而终止连接时触发。
(5) load:在接收到完整的响应数据时触发。
(6) loadend:在通信完成或者触发 error、abort 或 load 事件后触发。
(1) load事件
响应接收完毕后将触发 load 事件,因此也就没有必 要去检查 readyState 属性了。而 onload 事件处理程序会接收到一个
event 对象
,其target 属性就指向 XHR 对象实例
,因而可以访问到 XHR 对象的所有方法和属性。然而,并非所有浏览器都为这个事件实现了适当的事件对象。
(2)progress 事件
onprogress 事件处理程序会接收到一个 event 对象,其 target 属性是 XHR 对象,但 包含着
三个额外的属性:lengthComputable、position 和 totalSize。
其中,lengthComputable 是一个表示进度信息是否可用的布尔值,position 表示已经接收的字节数,totalSize 表示根据 Content-Length 响应头部确定的预期字节数。
4. 跨源资源共享
CORS(Cross-Origin Resource Sharing,跨源资源共享)
CORS 背后的
基本思想
,就是使用自定义的 HTTP 头部 让浏览器与服务器进行沟通,从而决定请求或响应是应该成功,还是应该失败。
比如一个简单的使用 GET 或 POST 发送的请求,它没有自定义的头部,而主体内容是 text/plain。在 发送该请求时,需要给它附加一个额外的
Origin 头部
,其中包含请求页面的源信息(协议、域名和端 口),以便服务器根据这个头部信息来决定是否给予响应。
Origin: http://www.nczonline.net
如果服务器认为这个请求可以接受,就在
Access-Control-Allow-Origin 头部
中回发相同的源信息(如果是公共资源,可以回发"*")。
Access-Control-Allow-Origin: http://www.nczonline.net
如果没有这个头部,或者有这个头部但源信息不匹配,浏览器就会驳回请求。正常情况下,浏览器 会处理请求。注意,请求和响应都不包含 cookie 信息。
(1) IE对CORS的实现
XDR
(XDomainRequest)类型。这个对象与 XHR 类似,但能实现安全可靠的跨域通信。
XDR 与 XHR 的一些不同之处
:
- cookie 不会随请求发送,也不会随响应返回。
- 只能设置请求头部信息中的 Content-Type 字段。
- 不能访问响应头部信息。
- 只支持GET和POST请求。
- XDR 对象的 open()方法只接收两个 参数:请求的类型和 URL。
- 请求返回之后,会触发 load 事件, 响应的数据也会保存在 responseText 属性中
- 在接收到响应后,你只能访问响应的原始文本;没有办法确定响应的状态代码。
(2) 其他浏览器对CORS的实现
要请求位于另一个域中的资源,使用标准的 XHR 对象并在 open()方法中传入
绝对 URL
即可。
跨域 XHR 对象限制:
- 不能使用 setRequestHeader()设置自定义头部。
- 不能发送和接收 cookie。
- 调用 getAllResponseHeaders()方法总会返回空字符串。
(3) Preflighted Reqeusts
CORS 通过一种叫做 Preflighted Requests 的透明服务器验证机制支持开发人员使用自定义的头部、 GET 或 POST 之外的方法,以及不同类型的主体内容。在使用下列高级选项来发送请求时,就会向服务 器发送一个 Preflight 请求。这种请求使用 OPTIONS 方法,发送下列头部。
- Origin:与简单的请求相同。
- Access-Control-Request-Method:请求自身使用的方法。
- Access-Control-Request-Headers:(可选)自定义的头部信息,多个头部以逗号分隔。
Origin: http://www.nczonline.net
Access-Control-Request-Method: POST
Access-Control-Request-Headers: NCZ
发送这个请求后,服务器可以决定是否允许这种类型的请求。服务器通过在响应中发送如下头部与 浏览器进行沟通。
- Access-Control-Allow-Origin:与简单的请求相同。
- Access-Control-Allow-Methods:允许的方法,多个方法以逗号分隔。
- Access-Control-Allow-Headers:允许的头部,多个头部以逗号分隔。
- Access-Control-Max-Age:应该将这个 Preflight 请求缓存多长时间(以秒表示)。
Access-Control-Allow-Origin: http://www.nczonline.net
Access-Control-Allow-Methods: POST, GET
Access-Control-Allow-Headers: NCZ
Access-Control-Max-Age: 172800016
(4) 带凭据的请求
默认情况下,跨源请求不提供凭据(cookie、HTTP 认证及客户端 SSL 证明等)。通过将 withCredentials 属性设置为 true,可以指定某个请求应该发送凭据。如果服务器接受带凭据的请 求,会用下面的 HTTP 头部来响应。
Access-Control-Allow-Credentials: true
5. 其他跨域技术
(1) 图像Ping
图像 Ping 是与服务器进行简单、单向的跨域通信的一种方式。 请求的数据是通过查询字符串形式发送的,而响应可以是任意内容,但通常是像素图或 204 响应。通过 图像 Ping,浏览器得不到任何具体的数据,但通过侦听 load 和 error 事件,它能知道响应是什么时 候接收到的。
(2) JSONP
JSONP 是 JSON with padding(填充式 JSON 或参数式 JSON)的简写,被包含在函数调用中的 JSON。
callback({ "name": "Nicholas" });
JSONP 由两部分组成:回调函数和数据
。回调函数是当响应到来时应该在页面中调用的函数。回调 函数的名字一般是在请求中指定的。而数据就是传入回调函数中的 JSON 数据。
JSONP 是通过动态