WebSocket
Web Socket(套接字)的目标是通过一个长时连接实现与服务器全双工、双向的通信。在JavaScript中创建Web Socket时,一个HTTP请求会发送到服务器以初始化连接。服务器响应后,连接使用HTTP的Upgrade头部从HTTP协议切换到Web Socket协议。这意味着Web Socket不能通过标准HTTP服务器实现,而必须使用支持该协议的专有服务器。
因为Web Socket使用了自定义协议,所以URL方案(scheme)稍有变化:不能再使用http://或https://,而要使用ws://和wss://。前者是不安全的连接,后者是安全的连接。在指定Web Socket URL时,必须包含URL方案,因为将来可能再支持其他方案。
使用自定义协议而非HTTP协议的好处是,客户端与服务器之间可以发送非常少的数据,不会对HTTP造成任何负担。使用更小的数据包让Web Socket非常适合带宽和延迟问题比较明显的移动应用。使用自定义协议的缺点是,定义协议的时间比定义Javascript API要长。Web Socket得到了所有主流浏览器支持。
# API
要创建一个新的Web Socket,就要实例化一个WebSocket对象并传入提供连接的URL:
let socket = new WebSocket("ws://www.example.com/server.php");
注意
必须给WebSocket构造函数传入一个绝对URL。同源策略不适用于WebSocket,因此可以打开任意站点的连接。至于是否来自特定源的页面通信,则完全取决于服务器(在握手阶段就可以确定请求来自哪里。)
浏览器会在初始化WebSocket对象之后立即创建连接。与XHR类似,WebSocket也有一个readyState属性表示当前状态。不过这个值与XHR中相应的值不一样。
值 | 实际值 | 含义 |
---|---|---|
WebSocket.OPENING | 0 | 连接正在建立 |
WebSocket.OPEN | 1 | 连接已经建立 |
WebSocket.CLOSING | 2 | 连接正在关闭 |
WebSocket.CLOSE | 3 | 连接已经关闭 |
WebSocket对象没有readystetechange事件,而是有与上述不同状态对应的其他事件。readyState值从0开始。
任何时候读可以调用close()方法关闭Web Socket连接:
socket.close()
调用close()之后,readyState立即变为2(连接正在关闭),并会在关闭后变为3(连接已经关闭)。
# 发送和接收数据
打开Web Socket之后,可以通过连接发送和接收数据。要向服务器发送数据,使用send()方法并传入一个字符串、ArrayBuffer或Blob:
let socket = new WebSocket("wa://www.example.com/server.php")
let stringData = "Hello world!"
let arrayBufferData = Uint8Array.from(['f','o','o'])
let blobData = new Blob(['f','o','o'])
socket.send(stringData)
socket.send(arrayBufferData.buffer)
socket.send(blobData)
2
3
4
5
6
7
8
9
服务器向客户发送消息时,WebSocket对象上会触发message事件。这个message事件与其他消息协议类似,可通过event.data属性访问到有效载荷:
socket.onmessage = function(evnet) {
let data = event.data
}
2
3
与通过send()方法发送的数据类似,event.data返回的数据也可能是ArrayBuffer或Blob。这由WebSocket对象的binaryType属性决定,该属性可能是blob或arrayBuffer。
# 其他事件
WebSocket对象在连接生命周期中可能触发3个其他事件。
事件名 | 事件 |
---|---|
open | 在连接成功时触发 |
error | 在发生错误时触发,连接无法存续 |
close | 在连接关闭时触发 |
注意
WebSocket对象不支持DOM Level2事件监听器,因此需要使用DOM Level 0 风格的事件处理程序来监听这些事件:
let socket = new WebSocket("wa://www.example.com/server.php")
socket.onopen = funciton() {
alert("Connection established")
}
socket.onerror = funciton() {
alert("Connection error")
}
socket.onclose = function() {
alert("Connection closed")
}
2
3
4
5
6
7
8
9
10
在这些事件中,只有close事件的event对象上有额外信息。
这个对象上有3个额外属性:
- wasClean : 一个布尔值,表示连接是否干净地关闭
- code : 一个来自服务器的数值状态码
- reason :一个字符串,包含服务器发来的消息
可以将这些信息显示给用户或记录到日志:
socket.onclose = function(event) {
console.log(event.wasClean, event.code, event.reason)
}
2
3