编写 WebSocket 客户端应用
WebSocket 客户端应用程序使用 WebSocket API 通过 WebSocket 协议与 WebSocket 服务器通信。
备注: 此特性在 Web Worker 中可用。
警告: 本文中的示例代码片段来自我们的 WebSocket 聊天应用示例,源代码在此处。
创建 WebSocket 对象
为了使用 WebSocket 协议通信,你需要创建一个 WebSocket
对象;这将会自动地尝试建立与服务器的连接。
WebSocket 构造函数接受一个必要参数和一个可选参数:
webSocket = new WebSocket(url, protocols);
url
-
要连接的 URL;这应当是 WebSocket 服务器会响应的 URL。
protocols
可选-
一个协议字符串或一个协议字符串数组。这些字符串用来指定子协议,这样一个服务器就可以实现多个 WebSocket 子协议(比如你可能希望一个服务器可以根据指定的
protocol
来应对不同的互动情况)。如果不指定协议字符串则认为是空字符串。
构造函数可能抛出以下异常:
SECURITY_ERR
-
尝试连接的端口被阻塞。
连接错误
如果尝试连接过程中发生错误,那么首先一个名为 "error" 的事件会被发送给 WebSocket
对象(然后调用其onerror
handler),然后 CloseEvent
被发送给WebSocket
(然后调用其 onclose
handler)以说明连接关闭的原因。
在 Firefox 11 中,通常会从 Mozilla 平台的控制台中收到一个描述性的错误信息,以及一个通过 CloseEvent
在 RFC 6455, Section 7.4 中定义的错误代码。
示例
本例创建了一个新的 WebSocket,连接到地址为 ws://www.example.com/socketserver
的服务器。请求中命名了一个自定义的协议 "protocolOne",这一部分可以省略。
var exampleSocket = new WebSocket(
"ws://www.example.com/socketserver",
"protocolOne",
);
返回后,exampleSocket.readyState
参数为 CONNECTING
。一旦连接可以传送数据,readyState
就会变成 OPEN
。
如果你想建立一个支持协议可选的连接,你可以指定协议的列表:
var exampleSocket = new WebSocket("ws://www.example.com/socketserver", [
"protocolOne",
"protocolTwo",
]);
一旦连接建立了(也就是说 readyState
是 OPEN
) exampleSocket.protocol
就会告诉你服务器选择了哪个协议。
上面的例子中 ws
替代了 http
,同样地 wss 也会替代 https
. 建立 WebSocket 链接有赖于 HTTP Upgrade mechanism, 所以当我们使用 ws://www.example.com
或者 wss://www.example.com
来访问 HTTP 服务器的时候协议会隐式地升级。
向服务器发送数据
一旦你的连接打开完成,你就可以向服务器发送数据了。对每一个要发送的消息使用 WebSocket
对象的 send()
方法:
exampleSocket.send("Here's some text that the server is urgently awaiting!");
你可以把数据作为字符串,Blob
,或者ArrayBuffer
来发送。
因为连接的建立是异步的,而且容易失败,所以不能保证刚创建 WebSocket 对象时使用 send()
方法会成功。我们至少可以确定企图在链接建立起来之后立马发送数据,可以通过注册 onopen
事件处理器解决:
exampleSocket.onopen = function (event) {
exampleSocket.send("Here's some text that the server is urgently awaiting!");
};
使用 JSON 发送对象
你可以方便地使用JSON 来向服务器发送复杂一些的数据。例如一个聊天程序与服务器交互的协议可以通过封装在 JSON 里的数据来实现:
// 服务器向所有用户发送文本
function sendText() {
// 构造一个 msg 对象,包含了服务器处理所需的数据
var msg = {
type: "message",
text: document.getElementById("text").value,
id: clientID,
date: Date.now(),
};
// 把 msg 对象作为 JSON 格式字符串发送
exampleSocket.send(JSON.stringify(msg));
// 清空文本输入元素,为接收下一条消息做好准备。
document.getElementById("text").value = "";
}
接收服务器发送的消息
WebSockets 是一个基于事件的 API;收到消息的时候,一个 "message" 消息会被发送到 onmessage
函数。为了开始监听传入数据,可以进行如下操作:
exampleSocket.onmessage = function (event) {
console.log(event.data);
};
接受与解析 JSON 对象
考虑在 使用 JSON 发送对象中提到的聊天应用客户端。客户端会收到各种类型的数据包,比如:
- 登陆握手
- 消息文本
- 用户列表更新
解析这些收到的消息的代码可能是这样的:
exampleSocket.onmessage = function (event) {
var f = document.getElementById("chatbox").contentDocument;
var text = "";
var msg = JSON.parse(event.data);
var time = new Date(msg.date);
var timeStr = time.toLocaleTimeString();
switch (msg.type) {
case "id":
clientID = msg.id;
setUsername();
break;
case "username":
text =
"<b>User <em>" +
msg.name +
"</em> signed in at " +
timeStr +
"</b><br>";
break;
case "message":
text = "(" + timeStr + ") <b>" + msg.name + "</b>: " + msg.text + "<br>";
break;
case "rejectusername":
text =
"<b>Your username has been set to <em>" +
msg.name +
"</em> because the name you chose is in use.</b><br>";
break;
case "userlist":
var ul = "";
for (i = 0; i < msg.users.length; i++) {
ul += msg.users[i] + "<br>";
}
document.getElementById("userlistbox").innerHTML = ul;
break;
}
if (text.length) {
f.write(text);
document.getElementById("chatbox").contentWindow.scrollByPages(1);
}
};
这里我们使用 JSON.parse()
来将 JSON 转换回原始对象,然后检查并根据其内容做下一步动作。
文本数据的格式
通过 WebSocket 连接收到的文本是 UTF-8 格式的。
在 Gecko 9.0 之前,一部分有效的 UTF-8 文本中的非字符将导致连接被中断。现在 Gecko 已经允许这些值。
关闭连接
当你不需要再用 WebSocket 连接了,调用 WebSocket close()
方法:
exampleSocket.close();
关闭连接前最好检查一下 socket 的 bufferedAmount
属性,以防还有数据要传输。
安全方面的考虑
WebSocket 不应当用于混合的上下文环境;也就是说,不应该在用 HTTPS 加载的页面中打开非安全版本的 WebSocket,反之亦然。而实际上一些浏览器也明确禁止这一行为,包括 Firefox 8 及更高版本。