Ajax与Comet
XMLHttpRequest对象
IE5是第一款引入XHR对象的浏览器。在IE5中,XHR对象是通过MSXML库中的一个ActiveX对象实现的。因此,在IE中可能会遇到三种不同版本的XHR对象,即MSXML2.XMLHttp
、MSXML2.XMLHttp.3.0
和MSXML2.XMLHttp.6.0
。
js
// 适用于IE7之前的版本
function createXHR () {
if (typeof arguments.callee.activeXString !== 'string') {
var version = ['MSXML2.XMLHttp.6.0', 'MSXML2.XMLHttp.3.0', 'MSXML2.XMLHttp'],
i,
len;
for (i = 0, len = version.length; i < len; i++) {
try {
new ActiveXObject(version[i]);
arguments.callee.activeXString = versions[i];
break;
} catch (e) {}
}
}
return new ActiveXObject(arguments.callee.activeXString);
}
IE7+、Firefox、Opera、Chrome和Safari都支持原生的XHR对象,在这些浏览器中创建XHR对象如下:
js
var xhr = new XMLHttpRequest();
XHR的用法
在使用XHR对象时,要调用的第一个方法是open()
,它接受3个参数:要发送的请求类型(get
、post
等)、请求的URL和表示是否异步发送请求的布尔值。
js
xhr.open('get', 'example.php', false);
要发送特定的请求,必须调用send()
方法。send()
接收一个参数,即要作为请求主体发送的数据。如果不需要,则必须传入null。
js
xhr.open('get', 'example.php', false);
xhr.send(null);
调用send()
之后,请求就会被分派到服务器。
由于这次请求是同步的,JavaScript代码会等到服务器响应之后再继续执行。在收到响应后,响应的数据会自动填充XHR对象的属性,相关属性以下:
responseText
:作为响应主体被返回的文本。responseXML
:如果响应内容类型是text/xml
或application/xml
,这个属性中将保存着包含响应数据的XML DOM文本。status
:响应的HTTP状态。statusText
:HTTP状态的说明。
在接收到响应后,第一步是检查status属性
,以确定响应已经成功返回。
js
xhr.open('get', 'example.php', false);
xhr.send(null);
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
alert(xhr.responseText);
} else {
alert('请求失败:' + xhr.status);
}
建议通过检测status
来决定下一步的操作,不要依赖statusText
。另外,无论内容类型是什么,响应主体的内容都会保存到responseText
属性中;而对于非XML数据而言,responseXML
属性的值将为null。
像前面这样发送同步请求当然没有什么,但多数情况下,我们还是要发送异步请求,才能让JavaScript继续执行而不必等待响应。此时,可以检测XHR对象的readyState属性
,该属性表示请求/响应过程的当前活动阶段。这个属性可取的值如下:
- 0:未初始化。尚未调用open()方法。
- 1:启动。已经open()但未send()。
- 2:已发送。已send()但未接收到响应。
- 3:接收。已接收到部分响应数据。
- 4:完成。已经接收到全部响应数据,而且已经可以在客户端使用了。
只要readyState属性
的值改变,都会触发一次readystatechange事件
。
js
var xhr = new XMLHttpRequest();
xhr.open('get', 'example.php', true);
xhr.send(null);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
alert(xhr.responseText);
} else {
alert('请求失败:' + xhr.status);
}
};
HTTP头部信息
每个HTTP请求和响应都会带有相应的头部信息。XHR对象也提供了操作这两种头部信息(请求头和响应头)的方法。
默认情况下,在发送XHR请求的同时,还会发送下列头部信息。
Accept
:浏览器能够处理的内容类型。Accept-Charset
:浏览器能够显示的字符集。Accept-Encoding
:浏览器能够处理的压缩编码。Accept-Language
:浏览器当前设置的语言。Connection
:浏览器与服务器之间连接的类型。Cookie
:当前页面设置的任何Cookie。Host
:发出请求的页面所在的域。Referer
:发出请求页面的URL。User-Agent
:浏览器的用户代理字符串。
使用setRequestHeader()
方法可以设置自定义的请求头。这个方法接受两个参数:名称和值。要成功发送请求头,必须在调用open()
之后且在调用send()
之前调用setRequestHeader()
。
js
var xhr = new XMLHttpRequest();
xhr.open('get', 'example.php', true);
xhr.setRequestHeader('MyHeader', 'MyValue');
xhr.send();
调用XHR对象的getResponseHeader()
并传入头部字段名称,可以取得相应的响应头部信息。而调用getAllResponseHeaders()
可以取得一个包含所有头部信息的长字符串。
js
var myHeader = xhr.getResponseHeader('MyHeader');
var allHeaders = xhr.getAllResponseHeaders();
GET请求
GET是最常见的请求类型,最常用于向服务器查询某些信息。必要时,可以将查询字符串参数追加到URL末尾,以便将信息发送给服务器。对XHR而言,位于传于open()
方法的URL末尾的查询字符串必须经过正确的编码才行。
js
// 下面这个函数可以辅助向现在URL的末尾添加查询字符串参数
function addURLParam(url, name, value) {
url += url.indexOf('?') === -1 ? '?' : '&';
url += encodeURIComponent(name);
url += '=';
url += encodeURIComponent(value);
return url;
}
// 示例
var url = 'example.php';
url = addURLParam(url, 'name', 'Nicholas');
url = addURLParam(url, 'book', 'myBook');
xhr.open('get', url, false);
POST请求
使用频率仅次于GET的是POST请求,通常用于向服务器发送应该被保存的数据。POST请求应该把数据作为请求的主体提交。POST请求的主体可以包含非常多的数据,而且格式不限。
js
xhr.open('post', 'postexample.php', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
var form = document.getElementById('myForm');
xhr.send(serialize(form));
下面示例PHP文件的postexample.php
。
php
<?php
header('content-type: text/plain');
echo <<<EOF
Name: {$_POST['user-name']}
Email: {$_POST['user-email']}
EOF;
如果不设置Content-Type
头部信息,那么发送给服务器的数据就不会出现$_POST
变量中。这时候,要访问同样的数据,就必须借助$HTTP_RAW_POST_DATA
。
XMLHttpRequest 2级
FormData
XMLHttpRequest 2级定义了FormData类型,为序列化表单以及创建与表单格式相同的数据(用于XHR传输)提供了便利。
js
var data = new FormData();
data.append('name', 'Nicholas');
这个append()
接收两个参数:键和值。而通过向FormData构造函数传入表单元素,也可以用表单元素的数据预先向其填入键值对。
js
var data = new FormData(document.forms[0]);
创建了FormData的实例后,可以将它直接传给XHR的send()
。
js
var xhr = new XMLHttpRequest();
xhr.open('post', 'postexample.php', true);
var data = new FormData(document.forms[0]);
xhr.send(data);
使用FormData的方便之处体现在不必明确地在XHR对象上设置请求头信息。XHR对象能够识别传入的数据类型是FormData的实例,并配置适当的头部信息。
支持FormData的浏览器有Firefox4+、Safari5+、Chrome和Android3+版的WebKit。
超时设定
XMLHttpRequest 2级规范中为XHR对象添加了一个timeout属性
,表示请求在等待响应多少毫秒之后就终止。如果在规定的时间内浏览器还没接收到响应,那么就会触发timeout事件
,进而会调用ontimeout
事件处理程序。
js
var xhr = new XMLHttpRequest();
xhr.open('get', 'timeout.php', true);
xhr.timeout = 1000; // 将超时设置为1秒钟(仅适用于IE8+)
xhr.ontimeout = function () {
alert('请求超时');
}
xhr.send(null);
overrideMimeType()方法
overrideMimeType()
方法,用于重写XHR响应的MIME类型。
比如,服务器返回的MIME类型是text/plain
,但数据中实际包含的是XML。根据MIME类型,即使数据是XML,responseXML
属性中仍然是null。通过调用overrideMimeType()
,可以保证把响应当作XML而非纯文本来处理。
js
var xhr = new XMLHttpRequest();
xhr.open('get', 'text.php', true);
xhr.overrideMimeType('text/xml'); // 必须在send()之前
xhr.send(null);
支持overrideMimeType()
的浏览器有Firefox、Safari4+、Opera10.5和Chrome。
进度事件
Progress Events规范是W3C的一个工作草案,定义了与客户端服务器通信有关的事件。这些事件最早其实只针对XHR操作,但目前也被其他API借鉴。有以下6个进度事件。
loadstart
:在接收到响应数据的第一个字节时触发。progress
:在接收响应期间不断地触发。error
:在请求发生错误时触发。abort
:在因为调用abort()
方法而终止连接时触发。load
:在接收到完整的数据时触发。loadend
:在通信完成或者触发error
、abort
或load
事件后触发。
支持前5个事件的浏览器有Firefox3.5+、Safari4+、Chrome、IOS版Safari和Android版WebKit。Opera(从第11版开始)、IE8+只支持load事件。目前还没有浏览器支持loadend事件。
load事件
只要浏览器接收到服务器的响应不管其状态如何,都会触发load事件
。
js
var xhr = new XMLHttpRequest();
xhr.onload = function () {
if (xhr.status === 200) {
alert(xhr.responseText);
} else {
alert('请求失败:' + xhr.status);
}
}
xhr.open('get', 'altevents.php', true);
xhr.send(null);
progress事件
onprogress
事件处理程序会接收到一个event对象,其target属性
是XHR对象,但包含着三个额外的属性:lengthComputable
(进度信息是否可用的布尔值)、position
(已接收的字节数)和totalSize
(根据Content-Length响应头确定的预期字节数)。
js
var xhr = new XMLHttpRequest();
xhr.onload = function () {
if (xhr.status === 200) {
alert(xhr.responseText);
} else {
alert('请求失败:' + xhr.status);
}
}
xhr.onprogress = function (event) {
var divStatus = document.getElementById('status');
if (event.lengthComputable) {
divStatus.innerHTML = '已接收' + event.position + '/' + event.totalSize + '字节';
}
}
xhr.open('get', 'altevents.php', true);
xhr.send(null);
跨域源资源共享
通过XHR实现Ajax通信的一个主要限制,来源于跨域安全策略。默认情况下,XHR对象只能访问与包含它的页面位于同一个域中的资源。这种安全策略可以预防某些恶意行为。但是,实现合理的跨域请求对开发某些浏览器应用程序也是至关重要的。
CORS(Cross-Origin Resource Sharing,跨域源资源共享)是W3C的一个工作草案,定义了在必须访问跨源访问时,浏览器与服务器应该如何沟通。CORS背后的基本思想,就是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是否应该成功。
比如一个简单的GET或POST请求,它没有自定义的头部,而主体内容是text/plain
。在发送该请求时,需要给它附加一个额外的Origin头部
,其中包含请求页面的源信息(协议、域名和端口),以便服务器根据这个头部信息来决定是否给予响应。
http
Origin: http://www.humandetail.com
如果服务器认为这个请求呆以接受,就在Access-Control-Allow-Origin
头部中回发相同的源信息(如果是公共资源,可以回发'*'
)。
plain-text
Access-Control-Allow-Origin: http://www.humandetail.com
如果没有这个头部,或者有这个部位但源信息不匹配,浏览器就会驳回请求。正常情况下,浏览器都会处理请求。注意,请求和响应都不包含cookie信息。
IE对CORS的实现
微软在IE8中引入了XDR(XDomainRequest)类型。这个对象与XHR类似,但能实现可靠的跨域通信。XDR对象的安全机制部分实现了W3C的CORS规范。以下是XDR与XHR的一些不同之处:
- cookie不会随请求发送,也不会随响应返回。
- 只能设置请求头部信息的中的
Content-Type
字段。 - 不能访问响应头部信息。
- 只支持GET和POST请求。
这些变化使CSRF(Cross-Site Request Forgery,跨站点请求伪造)和XSS(Cross-Site Scripting,跨站点脚本)的问题得到了缓解。被请求的资源可以根据它认为合适的任意数据(用户代理、来源页面等)来决定是否设置Access-Control-Allow-Origin
头部。作为请求的一部分,Origin头部的值表示请求的来源域,以便远程资源明确地识别XDR请求。
XDR对象的使用方法与XHR非常相似。但XDR对象的open()
只接收两个参数:请求类型和URL。因为XDR所有的请求都是异步的,不能用它来创建同步请求。
js
var xdr = new XDomainRequest();
xdr.onload = function () {
alert(xdr.responseText);
}
xdr.onerror = function () {
alert('出错了!');
}
xdr.timeout = 1000;
xdr.ontimeout = function () {
alert('请求超时了!!!');
}
xdr.open('get', 'http://www.somewhere-else.com/page/');
xdr.send(null);
在请求返回前调用abort()
方法可以终止请求:
js
xdr.abort(); // 终止请求
为支持POST请求,XDR对象提供了contentType属性
,用来表示发送数据的格式:
js
var xdr = new XDomainRequest();
xdr.onload = function () {
alert(xdr.responseText);
}
xdr.onerror = function () {
alert('出错了!');
}
xdr.timeout = 1000;
xdr.ontimeout = function () {
alert('请求超时了!!!');
}
xdr.open('post', 'http://www.somewhere-else.com/page/');
xdr.contentType = 'application/x-www-urlencoded'
xdr.send('name=value&name2=value2');
其他浏览器对CORS的实现
Firefox3.5+、Safari4+、Chrome、IOS版Safari和Android版WebKit都通过XMLHttpRequest
对象实现了对CORS的原生支持。在尝试打开不同来源的资源时,无需额外编写代码就可以触发这个行为,只需要在open()
中传入绝对URL即可:
js
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
alert(xhr.responseText);
} else {
alert('请求失败:' + xhr.status);
}
}
xhr.open('get', 'http://www.somewher-else.com/page/', true);
xhr.send(null);
与IE中的XDR对象不同,通过跨域XHR对象可以访问status
和statusText
属性,而且还支持同步请求。跨域对XHR对象也有一些限制,但为了安全这些限制是必需的。
- 不能使用
setRequestHeader()
自定义头部。 - 不能发送和接收cookie。
- 调用
getAllResponseHeader()
总会返回空字符串。
由于无论同源请求还是跨源请求都使用相同的接口,因此对于本地资源,最好使用相对URL,在访问远程资源时再使用绝对URL。这样做能消除歧义,避免出现限制访问头部或本地cookie信息等问题。
Preflighted Requests
CORS通过一种叫做Preflighted Requests的透明服务器验证机制并支持开发人员使用自定义头部,GET或POST之外的方法,以及不同类型的主体内容。在使用下列高级选项来发送请求时,就会向服务器发送一个Preflight请求。这种请求使用OPTIONS方法,发送下列头部:
Origin
:与简单的请求相同。Access-Control-Request-Method
:请求自身使用的方法。Access-Control-Request-Headers
:(可选)自定义的头部信息,多个以逗号分隔。
以下是一个带有自定义头部NCZ的使用POST方法发送的请求:
http
Origin: http://www.humandetail.com
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请缓存多久(以秒表示)。
例如:
http
Access-Control-Allow-Origin: http://www.humandetail.com
Access-Control-Allow-Methods: POST,GET
Access-Control-Allow-Headers: NCZ
Access-Control-Max-Age: 1728000
Preflight请求结束后,结果将按照响应中指定的时间缓存起来。而为此付出的代价只是第一次发送这种请求时会多一次HTTP请求。
支持Preflight请求的浏览器包括Firefox3.5+、Safari4+和Chrome。IE10及更早版本都不支持。
带凭据的请求
默认情况下,跨源请求不提供凭据(cookie、HTTP认证及客户端SSL证明等)。通过将withCredentials
属性设置为true,可以指定某个请求应该发送凭据。如果服务器接受带凭据的请求,会用下面的HTTP头部来响应:
http
Access-Control-Allow-Credentials: true
支持这个属性的浏览器有Firefox3.5+、Safari4+和Chrome。IE10及更早版本都不支持。
跨浏览器的CORS
即使浏览器对CORS的支持程度不一样,但所有浏览器都支持简单的(非Preflight和不带凭据的)请求,因此有必要实现一个跨浏览器的方案:
js
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;
}
return xhr;
}
var request = createCORSRequest('get', 'http://www.somewher-else.com/page/');
if (request) {
request.onload = function () {
// 对request.responseText进行处理
}
request.send();
}
其他跨域请求
图像Ping
js
var img = new Image();
img.onload = img.onerror = function () {
alert('Done');
}
img.src = 'http://www.humandetail.com/test'
JSONP
JSONP是JSON with padding(填充式JSON或参数式JSON)的简写,是应用JSON的一种新方法。
js
callback({ 'name': 'Nicholas' });
JSONP由两部分组成:回调函数和数据。回调函数是当响应到来时应该在页面中调用的函数。回调函数的名字一般在请求中指定。而数据就是传入回调中的JSON数据。下面是一个典型的JSONP请求:
plain-text
http://freegeoip.net/json/?callback=handleResponse
JSONP是通过动态<script>元素
来使用的,使用时可以为src
属性指定一个跨域URL。因为JSONP是有效的JavaScript代码,所以在请求完成后,即在JSONP响应加载到页面中以后,就会立即执行。
js
function handlerResponse (response) {
alert('你的IP地址是' + response.ip + ',位于' + response.city + ', ' + response.region_name);
}
var script = document.createElement('script');
script.src = 'http://freegeoip.net/json/?callback=handlerResponse';
document.body.insertBefore(script, document.body.firstChild);
这个例子通过查询地理定位服务来显示你的IP和位置信息。
JSONP之所以在开发人员中极为流行,主要原因是它非常简单易用。与图像Ping相比,它的优点在于能够直接访问响应文本,支持在浏览器与服务器之间双向通信。不过JSONP也有两点不足。
首先,JSONP是从其他域中加载代码执行。如果其他域不安全,很可能会在响应中夹带一些恶意代码。
其次,要确定JSONP请求是否失败并不容易。虽然HTML5给<script>元素
新增了一个onerror
事件处理程序,但目前还没有得到任何浏览器支持。为此,开发人员不得不使用计时器检测指定时间内是否接收到了响应。但就算这些也不能尽如人意,毕竟不是每个用户上网的速度和带宽都一样。
Comet
Comet是Alex Russell发明的一个词,指的是一种更高级的Ajax技术(经常也有人称为“服务器推送”)。Ajax是一种从页面向服务器请求数据的技术,而Comet则是一种服务器向页面推送数据的技术。
有两种实现Comet的方式:长轮询和流。
长轮询是传统轮询的一个翻版,即浏览器定时向服务器发送请求,看有没有更新的数据。页面发送一个到服务器的请求,然后服务器一直保持连接打开,直到有数据可发送。发送完数据之后,浏览器关闭连接,随即又发起一个到服务器的新请求。这一过程在页面打开期间一直持续不断。
轮询的优势是所有浏览器都支持。使用XHR对象和setTimeout()
就能实现。而你要做的就是决定什么时候发送请求。
第二种流行的Comet实现是HTTP流。流不同于轮询,因为它在页面的整个生命周期内只使用一个HTTP连接。具体来说,就是浏览器向服务器发送一个请求,而服务器保持连接武打,然后周期性地向浏览器发送数据。比如,下面这段PHP代码就是采用流实现的服务器中常见的形式:
php
<?php
$i = 0;
while (true) {
echo 'Number is ' . $i;
flush();
sleep(10);
$i++;
}
所有服务器端语言都支持打印到输出缓存然后刷新(将输出缓存中的内容一次性全部发送到客户端)的功能。而这正是HTTP流的关键所在。
在Firefox、Safari、Opera和Chrome中,通过侦听readystatechange事件
及检测readyState
的值是否为3,就可以利用XHR对象实现HTTP流。
js
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回调函数
progress(result);
} else if (xhr.readyState === 4) {
finished(xhr.responseText);
}
};
xhr.send(null);
return xhr
}
var client = createStreamingClieng('streaming.php', function (data) {
alert('Received: ' + data);
}, function (data) {
alert('Done!');
});
服务器发送事件
SSE(Server-Sent Events,服务器发送事件)是围绕只读Comet交互推出的API或者模式。SSE API 用于创建到服务器的单向连接,服务器通过这个连接可以发送任意数量的数据。服务器响应的MIME类型必须是text/event-stream
,而且是浏览器中的JavaScript API能解析格式输出。SSE支持短轮询、长轮询和HTTP,而且能在断开连接时自动确定何时重新连接。
支持SSE的浏览器有Firefox6+、Safari5+、Opera 11+、Chrome和IOS4+版Safari。
SSE API
SSE的JavaScript API与其他传递消息的JavaScript API很相似。要预订新的事件流,首先要创建一个新的EventSource
对象,并传入一个入口点:
js
var soruce = new EventSource('myevents.php');
注意,传入的URL必须与创建对象的页面同源(相同的URL模式、域及端口)。EventSource的实例有一个readyState属性
,值为0表示正连接到服务器,为1表示打开了连接,为2表示关闭了连接。
另外,还有三个事件:
open
:在建立连接时触发。message
:在从服务器接收到新事件时触发。error
:在无法建立连接时触发。
就一般的用户而言,onmessage
事件处理程序也没有什么特别的。
js
source.onmessage = function (event) {
var data = event.data;
// 处理数据
}
服务器发回的数据以字符串的形式保存在event.data
中。
默认情况下,EventSource对象会保持与服务器的活动连接。如果连接断开,还会重新连接。如果想关闭连接可以使用close()
方法。
js
source.close();
事件流
所谓的服务器事件会通过一个持久的HTTP响应发送,这个响应是MIME类型为text/event-stream
。响应的格式是纯文本,最简单的情况是每个数据项都带有前缀data:
,例如:
plain-text
data: foo
data: bar
data: foo
data: bar
对以上响应而言,事件流中的第一个message事件
返回的event.data
值为foo,第二个为bar,第三个为foo\nbar
(注意中间的换行符)。
通过id:
前缀可以给特定的事件指定一个关联的ID,这个ID行位于data:
行前面或后面皆可:
plain-text
data: foo
id: 1
id: 2
data: bar
设置了ID后,EventSource对象会跟踪上一次触发的事件。如果连接断开,会向服务器发送一个包含名为Last-Event-ID
的特殊HTTP头部的请求,以便服务器知道下一次该触发哪个事件。在多次连接的事件流中,这种机制可以确保浏览器以正确的顺序收到连接的数据段。
Web Sockets
要说最令人津津乐道的新浏览器API,就得数Web Sockets了。Web Sockets的目标是在一个单独的持久连接上提供全双工、双向通信。在JavaScript中创建了Web Socket之后,会有一个HTTP请求发送到浏览器以发起连接。在取得服务器响应后,建立的连接会使用HTTP升级从HTTP协议交换为Web Socket协议。也就是说,使用标准的HTTP服务器无法实现Web Sockets,只有支持这种协议的专门服务器才能正常工作。
由于Web Sockets使用了自定义协议,所以URL模式也略有不同。未加密的连接不再是http://
而是ws://
;加密的连接则是wss://
。在使用Web Socket URL时,必须带着这个模式,因为将来还有可能支持其他模式。
目前支持Web Sockets的浏览器有Firefox6+、Safari5+、Chrome和IOS4+版Safari。
Web Sockets API
js
var socket = new WebSocket('ws://www.example.com/server.php');
实例化了WebSocket对象后,浏览器就会马上尝试创建连接。与XHR类似,WebSocket也有一个表示当前状态的readyState属性
。不过,这个属性与XHR并不相同,而是如下所示:
WebSocket.OPENING(0)
:正在建立连接。WebSocket.OPEN(1)
:已建立连接。WebSocket.CLOSING(2)
:正在关闭连接。WebSocket.CLOSE(3)
:已关闭连接。
WebSocket没有readystatechange事件
;不过,它有其他事件,对应着不同的状态。readyState
的值永远从0开始。
要关闭连接,可以在任何时候调用close()
。调用后,readyState
的值立即变为2,而在关闭连接后就会变成3。
js
socket.close();
发送和接收数据。
要向服务器发送数据,使用send()
方法,并传入任意字符串即可:
js
socket.send('Hello world!');
因为Web Sockets只能通过连接发送纯文本数据,所以对于复杂结构的数据,在通过连接发送之前,必须进行序列化。
js
var message = {
time: new Date(),
text: 'Hello world!',
clientId: 'asdfp9834rew'
};
socket.send(JSON.stringify(message));
当服务器向客户端发来消息时,WebSocket对象会触发message事件
。
js
socket.onmessage = function (event) {
var data = event.data;
// 处理数据
}
其他事件
WebSocket对象还有其他三个事件,在连接生命周期的不同阶段触发:
open
:在成功建立连接时触发。error
:在出错时触发,连接不能持续。close
:在连接关闭时触发。
WebSocket对象不支持DOM 2级事件侦听器,因此必须使用DOM 0级语法分别定义每个事件处理程序。
js
var socket = new WebSocket('ws://www.example.com/server.php');
socket.onopen = function () {
console.log('成功建立连接');
};
socket.onerror = function () {
console.log('注意,出错了!');
};
socket.onclose = function () {
console.log('连接已关闭');
}
在这三个事件中,只有close事件的event对象有额外的信息。这个事件的事件对象有三个额外的属性:wasClean
(布尔值,表示连接是否已经明确地关闭)、code
(服务器返回的数值状态码)和reason
(字符串,服务器返回的消息)。