Ajax与Comet
1.XMLHttpRequest对象
IE5是第一款引入XHR对象的浏览器,但XHR对象是通过MSXML库中的一个ActiveX对象实现的。
兼容各个浏览器
2.XHR的用法
在使用XHR对象时,调用的一个方法是open(),它接收三个参数:要发送的请求的类型(“get”、“post”等)、
请求的URL和表示是否异步发送请求的布尔值。
如果要发送特定的请求,必须使用send()方法:
send()方法接收一个参数,即要作为请求主体发送的数据。如果不需要通过请求主体发送数据,则必须传入null.
在收到响应后,响应的数据会自动填充XHR对象的属性:
responseText: 作为响应主体被返回的文本。
responseXML: 如果响应的内容类型是“text/xml”或“application/xml”,这个属性中将保存包含着响应数据的XML DOM文档。
status: 响应的HTTP状态。
statusText: HTTP状态的说明。
在接收到响应后,第一步是检查status属性,以确定响应已成功返回。
状态码为304表示请求的资源并没有被修改,可以直接使用浏览器中缓存的版本。
在多数情况下,我们需要发送异步请求,才能让Javascript继续执行而不必等待响应。所以需要检测XHR对象的readyState属性,该属性表示请求/响应过程的当前活动阶段,有以下值:
0:未初始化。尚未调用open()方法。
1:启动。已经调用open()方法,但尚未调用send()方法
2:发送。已经调用send()方法,但尚未接收到响应
3:接收。已经接收部分响应数据。
4:完成。已经接收到全部响应数据,而且已经可以在客户端使用。
当readyState值改变时,将触发readyStatechange事件。
在接收到响应之前还可以调用abort()方法来取消异步请求:xhr.abort()。
3.HTTP头部信息
Accept:浏览器能够处理的内容类型
Accept-Charset:浏览器能够显示的字符集
Accept-Encoding:浏览器能够处理的压缩编码
Accept-Language:浏览器当前设置的语言
Connection:浏览器与服务器之间连接的类型
Cookie:当前页面设置的任何Cookie
Host:发出请求的页面所在的域
Referer:发出请求的页面URL
User-Agent:浏览器的用户代理字符串
可以使用setRequestHeader()方法设置自定义的请求头部信息。
这个方法接收两个参数:头部字段的名称和头部字段的值。
要想成功发送请求头部信息,必须在调用open()方法之后且调用send()方法之前调用setRequestHeader()。
获取头部信息,可以使用XHR对象的getResponseHeader()方法并传入头部字段名称,可以取得相应的响应头部信息。
而调用getAllResponseHeaders()方法则可以取得一个包含所有头部信息的长字符串。
4.GET请求
GET是最常见的请求类型,最常用于向服务器查询某些信息。
使用GET请求经常发生的一个错误,就是查询字符串的格式有问题。
下面这个函数可以辅助向现有URL的末尾添加查询字符串参数:
5.POST请求
通常用于向服务器发送应该被保存的数据。
XMLHttpRequest 2级
1.FormData
为了实现表单数据的序列化,XMLHttpRequest 2级为此定义了FromData类型。FormData为序列化表单以及创建与表单格式相同的数据(用于通过XHR传输)提供了便利。
创建了一个FormData表单对象,通过append()方法向表单中传入表单字段的名字和字段中包含的值。
也可以通过向FormData构造函数中传入表单元素。
2.超时设定(仅仅IE8支持)
IE8为XHR对象添加了一个timeout属性,表示请求在等待响应多少毫秒之后就终止。
在给timeout设置一个数值后,如果在规定时间内浏览器还没有接收到响应,那么就会触发timeout事件,进而调用ontimeout事件处理程序。
如果在超时终止请求之后再访问status属性,会导致错误,所以要将检查status属性的语句放在try-catch中。
3.overrideMimeType()方法
firefox最早引入overrideMimeType()方法,用于重写XHR响应的MIME类型。
进度事件
Progress Events规范是W3C的一个工作草案,定义了与客户端服务器通信有关的事件。
有以下6个进度事件:
loadstart:在接收到响应数据的第一个字节时触发。
progress:在接收响应期间持续不断地触发。(必须在调用open()方法之前添加onprogress()事件处理程序)
error:在请求发生错误时触发。
abort:在因为调用abort()方法而终止连接时触发。
load:在接收到完整的响应数据时触发。
loadend:在通信完成或者触发error、abort或load事件后触发。
跨域资源共享(CORS)
CORS背后的基本思想,就是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功,还是应该失败。
CSRF:跨域请求伪造
XSS:跨站点脚本
IE对CORS实现主要是通过XDR对象来实现,XDR对象与XHR类似,所有XDR请求都是异步的。
CORS通过一种叫做Prefighted Request的透明服务器验证机制支持开发人员使用自定义的头部、GET或POST之外的方法,以及不同类型主体内容。
检测XHR是否支持CORS的最简单方式,就是检查是否存在withCredentials属性
跨浏览器的CORS实现:
其他跨域技术
1.图像Ping
第一种跨域技术是使用<img>标签。因为加载图像不存在跨域问题。
动态创建图像经常用于图像Ping。图像Ping是与服务器进行简单、单向的跨域通信的一种方式。
请求的数据是通过查询字符串形式发送的,而响应可以是任意内容,但通常是像素图或204响应。
eg:
var img = new Image();
img.onload = img.onerror = function(){
alert(“Done!”);
}
img.src = “http://www.example.com/test?name=Peter“;
图像Ping最常用于跟踪用户点击页面或动态广告曝光次数。
图像Ping有两个缺点:一是只能发送GET请求;二是无法访问服务器的响应文本。
2.JSONP(JSON with padding 填充式JSON或参数式JSON)
JSONP由两部分组成:回调函数和数据。
通过查询字符串来指定JSONP服务的回调函数是很常见的。
JSONP是通过动态<script>元素来使用,使用时可以为src属性指定一个跨域URL。
JSONP的优点是:能够直接访问响应文本,支持在浏览器与服务器之间双向通信。
不足:JSONP是从其他域中加载代码执行,如果其他域不安全,很可能会在响应中夹带一些恶意代码;
其次要确定JSONP请求是否失败并不容易。
Comet
Comet指的是一种更高级的Ajax技术(经常也有人称为“服务器推送”)。
Ajax是一种从页面向服务器请求数据的技术,而Comet则是一种服务器向页面推送数据的技术。
Comet能够让信息近乎实时地被推送到页面上,非常适合处理体育比赛的分数和股票报价。
有两种实现Comet的方式:长轮询和流。
长轮询是传统轮询(短轮询)的一个翻版,即浏览器定时向服务器发送请求,看有没有更新的数据。
而长轮询是把短轮询颠倒了。页面发起一个到服务器的请求,然后服务器一直保持连接打开,直到有数据可发送。
无论短轮询还是长轮询,浏览器都要在接收数据之前,先发起对服务器的连接。
两者最大的区别在于服务器如何发送数据。短轮询是服务器立即发送响应,无论数据是否有效,而长轮询是等待发送响应。
以请客吃饭来讲述短轮询和长轮询:
短轮询就是,我(server)说要请客吃饭,然后你(browser)就不停地发短信问我“今天请客吃饭不?”,你的行为无疑是很浪费钱的(耗资源);
长轮询就是,我(server)说要请客吃饭,然后你(browser)就发条短信给我“下次请客吃饭记得叫我”,我就记得这件事,下次请客吃饭就会发短信通知你“我今天请客吃饭”。
第二种流行的Comet实现是HTTP流。流不同于上述两种轮询,因为它在页面的整个生命周期内只使用一个HTTP连接,即浏览器向服务器发送一个请求,而服务器保持连接打开,然后周期性地向浏览器发送数据。
在Firefox、Chrome、Opera等浏览器中,通过侦听readyStatechange事件以及检测readyState的值是否为3,就可以利用XHR对象实现HTTP流。当readyState值变为3时,responseText属性中就会保存接收到的所有数据。
使用XHR对象实现HTTP流的典型代码:
这个createStreamingClient()函数接收三个参数:要连接的URL、在接收到数据时调用的函数以及关闭连接时调用的函数。
服务器发送事件(SSE)
SSE是围绕只读Comet交互推出的API或者模式。SSE API用于创建到服务器的单向连接,服务器通过这个连接可以发送任意数量的数据。
1.SSE API
要预订新的事件流,首先要创建一个新的EventSource对象,并传进一个同源的入口点:
EventSource的实例有一个readyState属性,值为0表示正连接到服务器,值为1表示打开了连接,值为2表示关闭了连接。另外还有三个事件:
open:在建立连接时触发。
message:在从服务器接收到新事件时触发。
error:在无法建立连接时触发。
123 source.onmessage = function(event){var data = event.data;}
如果想强制立即断开连接并且不再重新连接,可以调用close()方法:source.close();
2.事件流
服务器事件会通过一个持久的HTTP响应发送,这个响应的MIME类型为text/event-stream.
Web Sockets
Web Sockets的目标是在一个单独的持久连接上提供全双工、双向通信。
单工:如果在通信过程的任意时刻,信息只能从一方A传到一方B,则称为单工;
半双工:如果在通信过程的任意时刻,信息既可以由A传到B,又能够从B传到A,但只能由一个方向上的传输存在,则称为半双工;
全双工:如果在通信过程的任意时刻,线路上存在A到B和B到A的双向信号传输,则称为全双工。
过程:
在Javascript中创建了WebSocket之后,会有一个HTTP请求发送到浏览器以发起连接。在取得服务器响应后,建立的连接会使用HTTP升级从HTTP协议交换为Web Socket协议。也就是说使用标准的HTTP服务器无法实现Web Sockets,只有支持这种协议的专门服务器才能正常工作。
Web Sockets使用了自定义的协议,有特定的URL模式:ws://,加密的连接是:wss://
使用自定义协议而非HTTP协议的好处是:能够在客户端和服务器之间发送非常少量的数据,而不必担心HTTP那样字节级的开销。
缺点:制定协议的时间比制定JavaScript API的时间还要长。
1.Web Sockets API
必须给WebSocket构造函数传入绝对URL,并且可以是跨域的URL。
与XHR类似,WebSocket也有readyState属性:
WebSocket.OPENING(0):正在建立连接。
WebSocket.OPEN(1):已经建立连接。
WebSocket.CLOSING(2):正在关闭连接。
WebSocket.CLOSE(3):已经关闭连接。
WebSocket没有readystatechange事件,readyState的值永远从0开始。
2.发送和接收数据
WebSocket只能通过连接发送纯文本信息,对于复杂的数据结构,如JSON数据,必须在连接发送之前进行序列化。
当服务器向客户端发来消息时,WebSocket对象会触发message事件,返回的数据保存在event.data。
3.其他事件
open:在成功建立连接时触发;
error:在发生错误时触发,连续不能持续;
close:在连接关闭时触发。
在这三个事件中,只有close事件的event对象有额外信息,分别是:wasClean、code和reason。
安全
CSRF(跨站点请求伪造):未被授权系统有权访问某个资源的情况。
为确保通过XHR访问的URL安全,通行的做法就是验证发送请求者是否有权限访问相应的资源。
有效做法:
要求以SSL连接来访问可以通过XHR请求的资源;
要求每一次请求都要附带经过算法计算得到的验证码;
无效做法(对于防范CSRF攻击不起作用):
要求发送POST而不是GET请求——很容易改变;
检查来源URL以确定是否可信——来源记录很容易伪造;
基于cookie信息进行验证——很容易伪造。
不要将用户名和密码保存在Javascript代码中!!!