(一)XMLHttpRequest对象
1.创建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"],
len, i;
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.");
}
}
2.XHR属性
(1)responseText
(2)responseXML
(3)status响应的HTTP状态
(4)statusText状态说明 不建议依赖此属性
(5)readyState属性
代码 | 意义 |
---|---|
0 | 未初始化调用open |
1 | 调用open未send |
2 | 调用send未响应 |
3 | 接收到部分 |
4 | 完成 |
var xhr = createXHR();
xhr.onreadystatechange = function() {
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", "main.php", false);
xhr.send(null);
(6)如果使用this对象,在有的浏览器中会导致函数执行失败,或者导致错误发生。因此,使用实际的XHR对象实例变量是较为可靠的一种方式。
(7)xhr.abort() 调用这个方法接收响应之前取消异步请求。 调用此方法,xhr对象会停止触发事件,而且不再允许访问任何与响应有关的对象属性。在终止请求之后,还应该对xhr对象进行解引用操作。 内存原因,不建议使用xhr对象。
3.HTTP头部
请求头部:
(1)Accept浏览器能够处理的内容类型
(2)Accept-Charset浏览器能够显示的字符集
(3)Accept-Encoding浏览器能够处理的压缩编码
(4)Accept-Language浏览器当前设置的语言
(5)Connection浏览器与服务器之间连接的类型
(6)Cookie当前页面设置的任何Cookie
(7)Host发出请求页面所在的域
(8)Referer**发出请求页面的URL**
(9)User-Agent浏览器的用户代理字符串
响应头部:
(1)xhr.setRequestHeader(“MyHeader”, “My Value”);
(2)var allHeaders = xhr.getAllResponseHeaders(); 返回多行文本内容,
(3)var myHeader = xhr.getResponseHeader(“MyHeader”);
(4)建议使用自定义头部字段名称,不要使用浏览器正常发送的字段名称,否则有可能会影响服务器的响应。有的浏览器允许开发人员重写头部信息,有的浏览器则不允许。
4.GET请求
var xhr = null;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
}else {
xhr = new ActiveXObject('Microsoft.XMLHTTP');
}
var url = "./getpost.php?username=" + username + "&password=" + password;
xhr.open('get', url, false);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
var data = xhr.responseText;
if (data==1) {
document.getElementById("showInfo").innerHTML = "登录成功";
}else if (data==2) {
document.getElementById("showInfo").innerHTML = "用户名或密码错误";
}
}
}
}
xhr.send(null);
5.POST请求
(1)头部信息 添加表单提交时的头部信息 模仿表单提交
不设置Content-Type头部信息,发送给服务器的数据就不会出现在$_POST超级全局变量中。没有CT头部,必须借助$HTTP_RAW_POST_DATA
xhr.setRequestHeader(“Content-Type”, “application/x-www-form-urlencoded”);
(2)序列化
xhr.send(serialize(form)); //表单部分函数
(3)GET请求的速度可达POST请求的两倍。
var data = "username=" + username + "&password=" + password;
xhr.open('post',"./getpost.php", true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
var res = xhr.responseText;
if (res == 1) {
document.getElementById("showInfo").innerHTML = "登陆成功!";
}else {
document.getElementById("showInfo").innerHTML = "error";
}
}
}
}
xhr.send(data);
(二)XMLHttpRequest 2级
1.FormData
xhr.send(new FormData(form))
使用FormData不用明确设置请求头部,自动配置适当的头部信息。
2.超时设定 (仅IE8支持)
xhr.timeout = 1000;
xhr.ontimeout = function() {
//超时后的操作
}
超时终止请求之后调用status会报错,为避免错误将status放在try/catch里。
3.overrideMimeType()
F S C O支持
响应的MIME类型决定了XHR对象如何处理。
xhr.overrideMimeType(“text/xml”)
当做XML处理
(三)进度事件
1.load事件 替代readystatechange事件 Firefox
只要浏览器能接收到服务器的响应,不管状态如何,都会触发load事件。 必须检测status
xhr.onload = function() {
if ((xhr.status >= 200 && xhr.status <300) || xhr.status == 304) {
console.log(xhr.responseText);
}else {}
}
2.progress事件
必须定义在open事件之前
event的target是xhr对象,包含三个额外属性 lengthComputable表示一个进度信息是否可用的布尔值
xhr.onprogress = function(event) {
if (event.lengthComputable) {
console.log(event.position + " " + event.totalSize + "bytes");
}
}
(四)跨域资源共享 CORS
什么是跨域?
通过 XHR 实现 Ajax 通信的一个主要限制,来源于跨域安全策略。默认情况下,XHR 对象只能访 问与包含它的页面位于同一个域中的资源。这种安全策略可以预防某些恶意行为。但是,实现合理的跨 域请求对开发某些浏览器应用程序也是至关重要的。简单的说即为浏览器限制A站点下的js代码对B站点下的url进行ajax请求。
ajax跨域请求方式有哪些?
(1)jsonp常用 动态 script标签的src属性
(2)iframe不常用
(3)服务端设置允许的网站请求数据 不常用
(5)artTemplate
(6)图像PING
(7)comet
(8)SSE
(9)WEB SOCKET
1.CORS的基本思想
使用自定义的HTTP头部让浏览器与服务器沟通,从而决定请求或响应是否应该成功。
2.请求、响应头部
请求加额外Origin头部
响应加Access-Control-Allow-Origin头部
请求和响应都不包含cookie信息
3.IE对CORS实现 XDR(XDomainRequest)实现安全可靠的跨域通信
(1)与XHR的不同之处 使CSRF(跨站点请求伪造)、XSS(跨站点脚本)问题得到缓解
cookie不会随请求发送,也不会随响应返回
只能设置请求头部信息中的Content-Type字段
不能访问响应头部信息
只支持GET和POST请求
被请求的资源可以根据它认为合适的任意数据来决定是否设置响应头部。作为请求的一部分,Origin头部的值表示请求的来源域,以便远程资源明确的识别XDR请求。
(2)XDR都是异步的,不能执行同步请求。
(3)只要响应有效,触发load事件,失败(包括没有响应头部)触发error事件,除了错误本身之外,没有其他信息可用。导致失败因素很多,不要忘记通过onerror事件处理程序来捕获事件。
var xdr = new XDomainRequest();
xdr.onload = function() {};
xdr.onerror = function() {};
xdr.timeout=1000;
xdr.ontimeout = function() {};
xdr.open("get", "http://www.somewhere-else.com/page/");
xdr.send(null);
(4)xdr.abort()方法终止请求
(5)contentType属性
xdr.open("post", "http://www.somewhere-else.com/page/");
xdr.contentType = “application/x-www-form-urlencoded”;
xdr.send(“name1=value1&name2=value2”);
4.其它浏览器对CORS的实现
(1)XHR 可以访问status和statusText属性 支持同步
安全限制:
不能使用setRequestHeader()设置自定义头部
不能发送和接收cookie
调用getAllResponseHeaders()返回空字符串
对于本地资源,最好使用相对URL,访问远程资源使用绝对URL。避免出现限制访问头部或本地cookie信息等问题
(2)Preflighted Requests 透明服务器验证机制 IE10- 不支持
允许开发人员使用其它方法,不同类型的主体内容
向服务器发送Preflight请求,这种请求使用OPTIONS方法
Origin: http://www.nczonline.net
Access-Control-Request-Method: POST
Access-Control-Request-Header: NCZ
服务器发送的响应头部:
Access-Control-Allow-Origin: http://www.nczonline.net
Access-Control-Allow-Methods: POST, GET
Access-Control-Allow-Headers: NCZ
Access-Control-Max-Age: 1728000
Preflight请求结束后,结果将按照响应中指定的事件缓存起来,而为此付出的代价只是第一次发送这种请求时会多一次http请求。
(3)带凭据的请求
凭据: cookie HTTP认证 客户端SSL证明
请求: withCredentials属性设置为true,可以指定某个请求应该发送凭据。
服务器对此的响应: Access-Control-Allow-Credentials: true 表示接受带凭据的请求
如果带凭据的请求,服务器没有此头部,浏览器不会把响应交给js,responseText中将是空字符串,status值为0,调用onerror。
5.跨浏览器
//检测XHR是否支持CORS最简单的方式就是检测withCredientials属性
function createCORSRequest(method, url) {
var xhr = new XMLHttpRequest();
if ("withCredientials" in xhr) {
xhr.open(method, url, true);
}else if (typeof XDomainRequest != "undefined") {
xhr = new XDomainRequest();
xhr.open(methodm url);
}else {
return null;
}
return xhr;
}
var request = createCORSRequest("get", "http://www.somewhere.com");
if (request) {
request.onload = function() {};
request.send();
}
XDR与XHR都支持的方法:
abort() onerror() onload() responseText() send()
(五)其它跨域技术
1.图像Ping
(1)是与服务器进行的简单、单向的跨域通信的一种方式。
(2)请求的数据可以是通过查询字符串形式发送的,而响应可以是任意内容,但通常是像素图或者204响应。浏览器得不到任何具体的数据。
(3) var img = new Image();
img.onload = img.onerror = function() {};
img.src = “http://www.example.com?name=Nicholas“;
(4)缺点: 只能发送GET请求,无法访问服务器的响应文本。
2.JSONP
(1) src与img都可以指定跨域url, 两者都有能力不受限制的从其它域加载资源。
function handleResponse(response) {};
var script = document.createElement("script");
script.src = "http://....../?callback=handleResponse";
document.body.insertBefore(script, document.body.firstChild);
(2)优点:直接访问响应文本 支持在浏览器与服务器之间双向通信
(3)不足:
①安全 其它域不安全,在响应中夹杂恶意代码,此时只能放弃jsonp
②难以判断是否请求失败 H5给script加onerror处理程序,没有浏览器支持。 只能判断时间,网速不同等因素也会导致误判。
3.Comet 服务器向页面推送数据的技术
(1)短轮循(传统轮循) 请求响应
(2)长轮循 请求后保持连接 服务器数据有变化时 发送响应 接收到响应后再重新发请求
流
(3)HTTP流 在页面的整个生命周期只使用一个http连接,接收部分先处理部分
function createStreamingClient(url, progress, finished) {
var xhr = new XMLHttpRequest(),
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(result); //处理刚刚接收到的部分
} else if(xhr.readyState == 4) {
finished(xhr.responseText);//接收完成,处理全部
}
};
xhr.send(null);
return xhr;
}
4.服务器发送事件 SSE
创建服务器的单向连接,服务器响应的MIME类型必须是text/event-stream。
SSE支持短轮循,长轮循,HTTP流,能在断开连接时自动确定何时重新连接。
(1)SSE API
var source = new EventSource("myevents.php"); //url必须同源
source.readyState | 意义 |
---|---|
0 | 正连接到服务器 |
1 | 打开了连接 |
2 | 关闭了连接 |
事件 | 意义 |
---|---|
open | 连接时触发 |
message | 从服务器接收到新事件时触发 |
error | 在无法建立连接时触发 |
source.onmessage = function(event) {
var data = event.data;
}
//强制断开连接并且不再重新连接
source.close();
(2)事件流
text/event-stream 服务器响应
响应的格式是纯文本 event.data
每个值之间以一个换行符分隔,只有在包含data的数据行后有空行,才会触发message事件,因此服务器生成事件流不能忘记加这一行。
给特定事件指定关联ID:
data:foo
id:1
设置ID后,EventSource事件会跟踪上一次触发的事件,如果和服务器断开,会向服务器发送一个包含Last-Event-ID的特殊HTTP头部请求,以便服务器知道下一次该触发哪一个事件。保证了顺序。
5.Web Sockets
全双工、双向通信
js中创建web socket后,会有一个http请求发送到浏览器以发起连接,在取得服务器响应后,建立的连接会使用HTTP升级从HTTP协议交换为Web Socket协议,使用标准的http协议无法实现Web Socket,只有支持这种协议的专门服务器才能正常工作。
/ | Web Socket URL | 传统URL |
---|---|---|
未加密 | ws:// | http:// |
加密 | wss:// | https:// |
使用自定义协议的
优点:能够在客户端和服务端发送非常少量的数据,而不必担心HTTP那样字节级的开销。
缺点:制定协议的时间过长
(1)Web Socket API
//必须传入绝对URL
var socket = new WebSocket("ws://www.example.com/server.php");
readyState属性 | 状态 |
---|---|
WebSocket.OPENING(0) | 正在建立连接 |
WebSocket.OPEN(1) | 已经建立连接 |
WebSocket.CLOSING(2) | 正在关闭连接 |
WebSocket.CLOSE(3) | 已经关闭连接 |
WebSocket没有readyStateChange事件
socket.close(); 关闭连接
2.发送和接收数据
socket.send("hello");
socket.send(JSON.stringify(message)); //JSON转字符串
socket.onmessage = function(event) {
var data = event.data; //得到字符串
}
3.其它事件
open 正确建立连接
error 发生错误,连接不能持续
close 连接关闭时触发,event对象有三个额外事件。wasClean,code,reasn
该对象事件不支持DOM2事件侦听器,用DOM0级
socket.onopen = function() {
//do something
}
socket.onclose = function(event) {
console.log(event.wasClean + " " + event.code + " " + event.reason);
}
6.SSE与Web Socket
第一,是否有自由度建立和维护websocket服务器。
第二,双向通信用websocket,不能实现的话,使用SSE+XHR组合也能实现双向通信。
(六)安全
跨站点请求伪造 CSRF
解决方法:
1.要求以SSL连接来访问可以通过XHR请求的资源
2.要求每一次请求都要附带经过相应算法计算得到的验证码
不能防范CSRF攻击:这些都很容易伪造
1.get post 要求
2.来源url
3.cookie验证