21.Ajax与Comet
21.1.XMLHttpRequest对象
-
创建
var xhr = new XMLHttpRequest(); // IE7+, Firefox等等
21.1.1.XHR的用法
-
open()
:启动一个请求以备发送// 接受三个参数:请求类型,请求URL(相对于执行代码的当前页面或绝对路径),是否异步发送请求 xhr.open("get", "example.php", false);
-
send()
:发送请求 -
abort()
:取消异步请求 -
收到响应
-
响应的数据会自动填充XHR对象的属性
responseText
:作为响应主体被返回的文本responseXML
:如果响应的内容类型是"text/xml"或者"application/xml",这个属性将保存包含响应数据的XML DOM文档,对非XML数据而言,responseXML属性将为nullstatus
:响应的HTTP状态statusText
:HTTP状态说明
-
检测
status
属性并操作if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) { alert(xhr.responseText); } else { alert("Request was unsuccessful: " + xhr.status); }
-
-
XHR对象的
readyState
属性表示请求/响应过程的当前活动阶段-
0:未初始化。尚未调用
open()
方法 -
1:启动。已经调用
open()
方法,但尚未调用send()
方法 -
2:发送。已经调用
send()
方法,但尚未接收到响应 -
3:接受。已经接收到部分响应数据
-
4:完成。已经接收到全部响应数据,并且已经可以在客户端使用了
var xhr = new XMLHttpRequest(); // 0 xhr.open('get', 'http://localhost:3000/readystate'); // 1 xhr.onreadystatechange = function() { // 2, 3, 4 alert(xhr.readyState); if(xhr.readyState == 4) { console.log(xhr.responseText); } }; xhr.send();
-
21.1.2.HTTP头部信息
-
设置属性
Accept
:浏览器能够处理的内容类型Accepy-Charset
:浏览器能够显示的字符集Accept-Encoding
:浏览器能够处理的压缩编码Accept-Language
:浏览器当设置的语言Connection
:浏览器与服务器之间连接的类型Cookie
:当前页面设置的任何CookieHost
:发送请求的页面所在的域Referer
:发送请求的页面的URI
-
用法
// 在调用 open() 方法之后且调用 send() 方法之前调用 setRequestHeader() xhr.open("get", "example.php", true); xhr.setRequestHeader("MyHeader", "MyValue"); // key && value xhr.send(null);
-
获取属性
var myHeader = xhr.getResponseHeader("MyHeader"); var allHeaders = xhr.getAllResponseHeaders();
21.1.3.GET请求
-
查询字符串中的每个拿书的名称和值必须使用
encodeURIComponent()
进行编码 -
所有的键值对都必须以和号
&
分隔xhr.open("get", "example.php?name1=value1&name2=value2", true);
function addURIParam(url, name, value) { url += (url.indexOf("?") == -1 ? "?" : "&"); url += encodeURIComponent(name) + "=" + encodeURIComponent(value); return url; }
21.1.4.POST请求
-
使用XHR模仿表单提交
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));
-
发送相同的数据,GET请求的速度最多可达POST请求的两倍
21.2.XMLHttpRequest 2级
21.2.1.FormData
var data = new FormData();
data.append("name", "ming");
xhr.open("post", "postexample.php", true);
var form = document.getElementById("user-info");
xhr.send(new FormData(form));
- 使用FormData的方便之处体现在不必明确地在XHR对象上设置请求头部。XHR对象能够识别传入的数据类型是FormData的实例,并配置适当的头部信息
21.2.2.超时设定
21.2.3.overideMimeType()方法
- 用于重写XHR响应的MIME类型
var xhr = creatXHR();
xhr.open("get", "text.php", true);
xhr.overrideMimeType("text/xml");
xhr.send(null);
21.3.进度事件
loadstart
:在接收到响应数据的第一个字节时触发progress
:在接收到响应期间持续不断地触发error
:在请求发生错误时触发abort
:在因为调用abort( )方法而终止连接时触发load
:在接受到完整的响应数据时触发loadend
:在通信完成或触发error、abort或load事件后触发
21.3.1.load事件
var xhr = createXHR();
xhr.onload = function() {
if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
alert(xhr.responseText);
} else {
alert("Request was unsuccessful: " + xhr.status);
}
};
xhr.open("get", "altevents.php", true);
xhr.send(null);
- 只要浏览器接收到服务器的响应,不管其状态如何,都会触发load事件
21.3.2.progress事件*
21.4.跨域资源共享
-
来源于跨域安全策略,默认情况下XHR对象只能访问域包含它的页面位于同一个域中的资源,这种安全策略可以预防某些恶意行为
-
CORS( Cross-Origin Resource Sharing,跨域资源共享 )
-
使用自定义的HTTP头部让浏览器与服务器进行沟通
-
发送请求时,需要额外附加Origin头部,其中包含请求页面的源信息( 协议、域名和端口 ),以便服务器根据这个头部信息来决定是否需要给予响应
//example Origin: http://www.nczonline.net
-
如果服务器认为这个请求可以接受,就在
Access-Control-Allow-Origin
头部回发相同的源信息,如果是公共资源,可以回发*
Access-Control-Allow-Origin: http://www.nczonline.net
-
请求和响应都不包含cookie信息
-
21.4.1.IE对CORS的实现
- IE8引入了XDR类型,缓解了CSRF和XSS
21.4.2.其他浏览器对CORS的实现
- 通过XMLHttpRequest对象实现了对CORS的原生支持
21.4.3.Preflighted Requests
-
CORS通过一种叫做Preflighted Requests的透明服务器验证机制支持开发人员使用自定义的头部、GET或POST之外的方法,以及不同类型的主题内容
-
使用方法
-
客户端
Origin: http://www.nczonline.net Access-Control-Request-Method: POST // 逗号隔开 Access-Control-Request-Headers: NCZ
-
服务端
Access-Control-Allow-Origin: http://www.nczonline.net Access-Control-Allow-Origin: POST, GET Access-Control-Allow-Origin: NCZ Access-Control-Max-Age: 1728000
-
-
Preflight请求结束后,结果将按照响应中指定的时间啊缓存起来,而为此付出的代价只是多发送一次HTTP请求
21.4.4.带凭据的请求
-
默认情况下跨域请求不提供凭据( cookie,HTTP认证及客户端SSL证明等 )
-
通过将
withCredentials
属性设置为true,可以指定某个请求应该发送凭据 -
如果服务器接受带凭据的请求,会用下面的HTTP头部来响应
Access-Control-Allow-Credentials: true
-
如果发送的是带凭据的请求,但服务器的响应中没有包含这个头部,那么浏览器就不会把响应交给JS
21.4.5.跨浏览器的CORS
function createCORSRequest(method, url) {
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;
}
}
var request = createRequest("get", "http://www.somewhere-else.com/page/");
if(request){
request.onload = function() {
// 对response进行处理
};
request.send();
}
21.5.其他跨域技术
21.5.1.图像Ping
-
一个网页可以从任何网页中加载图像,不用担心跨不跨域
-
是在线广告跟踪浏览量的主要方式
-
请求通常是以查询字符串的形式发送的,而响应可以是任意内容
-
通过图像Ping,浏览器得不到任何具体的数据,但通过侦听load和error事件,它能知道响应是什么时候接收到的
-
实现
var img = new Image(); img.onload = img.onerror = function() { alert("Done"); }; img.src = "http://www.example.com/test?name=ming"
-
缺点
- 只能发送GET请求
- 无法访问服务器的响应文本,只能用于浏览器与服务器间的单向通信
21.5.2.JSONP
-
JSONP由两部分组成:回调函数和数据
- 回调函数是当响应到来时应该在页面中调用的函数,回调函数的名字一般是在请求中指定的
- 数据就是传入回调函数中的JSON数据
-
原理
-
JSONP通过动态
-
21.5.3.Comet#
- 实现方式
- 长轮询
- 流
21.5.4.服务端发送事件*
21.5.5.Web Sockets*
21.5.6.SSE与Web Socket2*
21.6.安全
- CSRF( Cross-Site Request Forgery ) 跨站请求伪造
- 未被授权的系统会伪造自己,让处理请求的服务器认为它是合法的
- 解决方法:验证发送者是否有权限访问相应的资源
- 要求以SSL连接来访问可以通过XHR请求的资源
- 要求每一次请求都要附带经过相应算法计算得到的验证码