Ajax与Comet

前端开发
2018年12月16日
634

XMLHttpRequest对象

IE5是第一款引入XHR对象的浏览器。在IE5中,XHR对象是通过MSXML库中的一个ActiveX对象实现的。因此,在IE中可能会遇到三种不同版本的XHR对象,即MSXML2.XMLHttpMSXML2.XMLHttp.3.0MSXML2.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个参数:要发送的请求类型(getpost等)、请求的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/xmlapplication/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:在通信完成或者触发errorabortload事件后触发。

支持前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对象可以访问statusstatusText属性,而且还支持同步请求。跨域对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(字符串,服务器返回的消息)。