小程序——WebSocket
WebSocket
一、概述
随着互联网的发展,传统的HTTP协议已经很难满足W©b应用日益复杂的需求了。近年来,随着HTML5的诞生,WebSocket协议被提出,它实现了浏览器与服务器的全双工通信,扩展了浏览器与服务端的通信功能,使服务端也能主动向客户端发送数据。
传统的HTTP协议是无状态的,每次请求(Request)都要由客户端(如浏览器)主动发起,服务端进行处理后返回Response结果。传统Web模式中客户端是主动方,服务端是被动方,服务端很难主动向客户端发送数据,对于信息变化不频繁的Wb应用来说传统模式是足够应付的。对于涉及实时信息交互的Wb应用,如带有即时通信、实时数据、订阅推送等功能的应用,上述模式带来了很大的不便。在WebSocket规范被提出之前,开发人员若要实现这些实时性较强的功能,经常会使用折中的解决方法:轮询(Polling)和Comet技术。后者本质上其实也是一种轮询,但有所改进。轮询是最原始实现实时Web应用的解决方案。轮询技术要求客户端以设定的时间间隔周期性地向服务端发送请求,频繁地查询是否有新的数据改动。明显地,这种方法会导致过多不必要的请求,浪费流量和服务器资源。
Comet技术可以分为长轮询和流技术。长轮询改进了上述的轮询技术,减少了无用的请求。它为某些数据设定过期时间,当数据过期后才会向服务端发送请求,这种机制适合数据改动不是特别频繁的情况。流技术通常是指客户端使用一个隐藏的窗口与服务端建立一个HTTP长连接,服务端会不断更新连接状态以保持HTTP长连接存活,据此,服务端就可以通过这条长连接主动将数据发送给客户端。
轮询和Comet技术都基于请求-应答模式,都不算是真正意义上的实时技术。它们的每一次请求、应答,在相同的头部信息上都浪费了一定流量,并且复杂度也较大。
伴随着HTML5推出的WebSocket,真正实现了Web的实时通信,使B/S模式具备了C/S模式的实时通信能力。WebSocket的工作流程是这样的:浏览器通过JavaScript向服务端发出建立WebSocket连接的请求,在WebSocket连接建立成功后,客户端和服务端就可以通过TCP连接传输数据。因为WebSocket连接本质上是TCP连接,所以不需要每次传输都带上重复的头部数据,它的数据传输量比轮询和Comet技术小很多。
微信小程序的WebSocket功能提供了如下几个接口:
| 接口 | 功能和用途 |
|---|---|
wx.connectSocket() |
创建WebSocket连接 |
wx.onSocketOpen() |
监听WebSocket打开 |
wx.onSocketError() |
监听WebSocket错误 |
wx.sendSocketMessage() |
发送WebSocket消息 |
wx.onSocketMessage() |
接收WebSocket消息 |
wx.closeSocket() |
关闭WebSocket连接 |
wx.onSocketClose() |
监听WebSocket关闭 |
二、WebSocket接口
2.1、SocketTask wx.connectSocket(Object object)
创建一个 WebSocket 连接。
- 参数:Object object
| 属性 | 类型 | 默认值 | 必填 | 说明 |
|---|---|---|---|---|
url |
string | 是 | 开发者服务器 wss 接口地址 | |
header |
Object | 否 | HTTP Header,Header 中不能设置 Referer | |
protocols |
Array.<string> | 否 | 子协议数组 | |
tcpNoDelay |
boolean | false | 否 | 建立 TCP 连接的时候的 TCP_NODELAY 设置 |
perMessageDeflate |
boolean | false | 否 | 是否开启压缩扩展 |
timeout |
number | 否 | 超时时间,单位为毫秒 | |
forceCellularNetwork |
boolean | false | 否 | 强制使用蜂窝网络发送请求 |
success |
function | 否 | 接口调用成功的回调函数 | |
fail |
function | 否 | 接口调用失败的回调函数 | |
complete |
function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
- 返回值:SocketTask
WebSocket 任务 - 并发数:
- 1.7.0 及以上版本,最多可以同时存在 5 个 WebSocket 连接。
- 1.7.0 以下版本,一个小程序同时只能有一个 WebSocket 连接,如果当前已存在一个 WebSocket 连接,会自动关闭该连接,并重新创建一个 WebSocket 连接。
wx.connectSocket({
url: 'wss://example.qq.com',
header:{
'content-type': 'application/json'
}
})
2.2、wx.onSocketOpen(function listener)
监听 WebSocket 连接打开事件。
- 参数:function listener
WebSocket 连接打开事件的监听函数
Object res:
| 属性 | 类型 | 说明 |
|---|---|---|
| header | object | 连接成功的 HTTP 响应 Header |
2.3、wx.onSocketError(function listener)
监听 WebSocket 错误事件。
- 参数:function listener
WebSocket 错误事件的监听函数
Object res
| 属性 | 类型 | 说明 |
|---|---|---|
| errMsg | string | 错误信息 |
2.4、wx.sendSocketMessage(Object object)
通过 WebSocket 连接发送数据。需要先 wx.connectSocket,并在 wx.onSocketOpen 回调之后才能发送。
- 参数:Object object
| 属性 | 类型 | 默认值 | 必填 | 说明 |
|---|---|---|---|---|
data |
string/ArrayBuffer | 是 | 需要发送的内容 | |
success |
function | 否 | 接口调用成功的回调函数 | |
fail |
function | 否 | 接口调用失败的回调函数 | |
complete |
function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
let socketOpen = false
let socketMsgQueue = []
wx.connectSocket({
url: 'test.php'
})
wx.onSocketOpen(function(res) {
socketOpen = true
for (let i = 0; i < socketMsgQueue.length; i++){
sendSocketMessage(socketMsgQueue[i])
}
socketMsgQueue = []
})
function sendSocketMessage(msg) {
if (socketOpen) {
wx.sendSocketMessage({
data:msg
})
} else {
socketMsgQueue.push(msg)
}
}
2.5、wx.onSocketMessage(function listener)
监听 WebSocket 接收到服务器的消息事件。
- 参数:unction listener
WebSocket 接收到服务器的消息事件的监听函数
Object res:
| 属性 | 类型 | 说明 |
|---|---|---|
| data | string/ArrayBuffer | 服务器返回的消息 |
2.6、wx.closeSocket(Object object)
关闭 WebSocket 连接。
- 参数:Object object
| 属性 | 类型 | 默认值 | 必填 | 说明 |
|---|---|---|---|---|
code |
number | 1000(表示正常关闭连接) | 否 | 一个数字值表示关闭连接的状态号,表示连接被关闭的原因。 |
reason |
string | 否 | 一个可读的字符串,表示连接被关闭的原因。这个字符串必须是不长于 123 字节的 UTF-8 文本(不是字符)。 | |
success |
function | 否 | 接口调用成功的回调函数 | |
fail |
function | 否 | 接口调用失败的回调函数 | |
complete |
function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
wx.connectSocket({
url: 'test.php'
})
//注意这里有时序问题,
//如果 wx.connectSocket 还没回调 wx.onSocketOpen,而先调用 wx.closeSocket,那么就做不到关闭 WebSocket 的目的。
//必须在 WebSocket 打开期间调用 wx.closeSocket 才能关闭。
wx.onSocketOpen(function() {
wx.closeSocket()
})
wx.onSocketClose(function(res) {
console.log('WebSocket 已关闭!')
})
2.7、wx.onSocketClose(function listener)
监听 WebSocket 连接关闭事件。
- 参数:function listener
WebSocket 连接关闭事件的监听函数
Object res:
| 属性 | 类型 | 说明 |
|---|---|---|
| code | number | 一个数字值表示关闭连接的状态号,表示连接被关闭的原因。 |
| reason | string | 一个可读的字符串,表示连接被关闭的原因。 |
2.8、案例
<view class="zong">
<view class="shang">
<view wx:for="{{messagelist}}" wx:for-index="idx" wx:for-item="itemName">
<view class="selfMessage" wx:if="{{itemName.type == 'self'}}">
<view class="nameInfo">{{itemName.name + " " + itemName.time}}</view>
<view class="detailMessage">{{itemName.message}}</view>
</view>
<view class="otherMessage" wx:else>
<view class="nameInfo">{{itemName.name + " " + itemName.time}}</view>
<view class="detailMessage">{{itemName.message}}</view>
</view>
</view>
</view>
<view class="xia">
<form report-submit bindsubmit="fasong">
<viwe class="inputArea">
<input type="text" name="inputValue" placeholder="{{placeholderText}}" class="message"/>
</viwe>
<button size="default" type="primary" form-type="submit" class="sendButton">发送</button>
</form>
</view>
</view>
Page({
data: {
placeholderText: "连接后端服务器中...",
messagelist: [],
socketOpen: false,
},
onLoad: function(options) {
console.log("将要连接后端服务器。")
wx.connectSocket({
url: 'ws://127.0.0.1:8080/ws'
});
wx.onSocketOpen((result) => {
console.log("连接后台服务器成功。")
this.setData({
placeholderText: "连接成功,请输入您的昵称。",
socketOpen: true
})
});
wx.onSocketMessage((res) => {
console.log("收到后端服务器内容:" + res.data);
var data = res.data;
var dataArray = data.split("_");
var newMessage = {
type: dataArray[0],
name: dataArray[1],
time: dataArray[2],
message: dataArray[3]
};
var newArray = this.data.messagelist.concat(newMessage);
this.setData({
messagelist: newArray,
placeholderText: "请输入聊天信息"
});
});
},
onUnload: function() {
wx.closeSocket();
},
fasong: function(e) {
if(e.detail.value.inputValue != "") {
if(this.data.socketOpen) {
wx.sendSocketMessage({
data: e.detail.value.inputValue
})
}
}
}
})
三、SocketTask
WebSocket 任务,可通过 wx.connectSocket() 接口创建返回。
3.1、SocketTask.close(Object object)
关闭 WebSocket 连接
- 参数:Object object
| 属性 | 类型 | 默认值 | 必填 | 说明 |
|---|---|---|---|---|
code |
number | 1000(表示正常关闭连接) | 否 | 一个数字值表示关闭连接的状态号,表示连接被关闭的原因。 |
reason |
string | 否 | 一个可读的字符串,表示连接被关闭的原因。这个字符串必须是不长于 123 字节的 UTF-8 文本(不是字符)。 | |
success |
function | 否 | 接口调用成功的回调函数 | |
fail |
function | 否 | 接口调用失败的回调函数 | |
complete |
function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
3.2、SocketTask.onClose(function listener)
监听 WebSocket 连接关闭事件
- 参数:function listener
WebSocket 连接关闭事件的监听函数
Object res:
| 属性 | 类型 | 说明 |
|---|---|---|
| code | number | 一个数字值表示关闭连接的状态号,表示连接被关闭的原因。 |
| reason | string | 一个可读的字符串,表示连接被关闭的原因。 |
3.3、SocketTask.onError(function listener)
监听 WebSocket 错误事件
- 参数:function listener
WebSocket 错误事件的监听函数
Object res:
| 属性 | 类型 | 说明 |
|---|---|---|
| errMsg | string | 错误信息 |
3.4、SocketTask.onMessage(function listener)
监听 WebSocket 接收到服务器的消息事件
- 参数:function listener
WebSocket 接收到服务器的消息事件的监听函数
Object res:
| 属性 | 类型 | 说明 |
|---|---|---|
| data | string/ArrayBuffer | 服务器返回的消息 |
3.5、SocketTask.onOpen(function listener)
监听 WebSocket 连接打开事件
- 参数:function listener
WebSocket 连接打开事件的监听函数
Object res:
| 属性 | 类型 | 说明 |
|---|---|---|
| header | object | 连接成功的 HTTP 响应 Header |
| profile | Object | 网络请求过程中一些调试信息 |
其中profile结构如下:
| 结构属性 | 类型 | 说明 |
|---|---|---|
| fetchStart | number | 组件准备好使用 SOCKET 建立请求的时间,这发生在检查本地缓存之前 |
| domainLookUpStart | number | DNS 域名查询开始的时间,如果使用了本地缓存(即无 DNS 查询)或持久连接,则与 fetchStart 值相等 |
| domainLookUpEnd | number | DNS 域名查询完成的时间,如果使用了本地缓存(即无 DNS 查询)或持久连接,则与 fetchStart 值相等 |
| connectStart | number | 开始建立连接的时间,如果是持久连接,则与 fetchStart 值相等。注意如果在传输层发生了错误且重新建立连接,则这里显示的是新建立的连接开始的时间 |
| connectEnd | number | 完成建立连接的时间(完成握手),如果是持久连接,则与 fetchStart 值相等。注意如果在传输层发生了错误且重新建立连接,则这里显示的是新建立的连接完成的时间。注意这里握手结束,包括安全连接建立完成、SOCKS 授权通过 |
| rtt | number | 单次连接的耗时,包括 connect ,tls |
| handshakeCost | number | 握手耗时 |
| cost | number | 上层请求到返回的耗时 |
3.6、SocketTask.send(Object object)
通过 WebSocket 连接发送数据
- 参数:Object object
| 属性 | 类型 | 默认值 | 必填 | 说明 |
|---|---|---|---|---|
data |
string/ArrayBuffer | 是 | 需要发送的内容 | |
success |
function | 否 | 接口调用成功的回调函数 | |
fail |
function | 否 | 接口调用失败的回调函数 | |
complete |
function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
3.7、示例
** 1. 发送消息**
socketTask.send({
data: JSON.stringify({ message: 'Hello' }),
success() {
console.log('发送成功')
},
fail(err) {
console.error('发送失败', err)
}
})
2. 接受消息
socketTask.onMessage((res) => {
console.log('收到消息:', res.data)
// 处理消息
const data = JSON.parse(res.data)
})
3. 监听连接打开
socketTask.onOpen(() => {
console.log('WebSocket连接已打开')
console.log('当前状态:', socketTask.readyState)
})
4. 监听连接关闭
socketTask.onClose((res) => {
console.log('连接已关闭', res)
// res.code: 关闭码
// res.reason: 关闭原因
})
5. 监听错误
socketTask.onError((err) => {
console.error('WebSocket错误:', err)
})
6. 关闭连接
// 可选参数
socketTask.close({
code: 1000, // 关闭码,默认1000
reason: '正常关闭', // 关闭原因
success() {
console.log('关闭成功')
},
fail(err) {
console.error('关闭失败', err)
}
})
完整使用示例:
// 创建连接
const createWebSocket = () => {
const socketTask = wx.connectSocket({
url: 'wss://example.com/ws',
header: { 'Content-Type': 'application/json' }
})
// 监听连接打开
socketTask.onOpen(() => {
console.log('连接已建立')
// 发送心跳
setInterval(() => {
if (socketTask.readyState === 1) {
socketTask.send({ data: 'ping' })
}
}, 30000)
})
// 监听消息
socketTask.onMessage((res) => {
try {
const data = JSON.parse(res.data)
handleMessage(data)
} catch (e) {
console.log('接收文本消息:', res.data)
}
})
// 监听错误
socketTask.onError((err) => {
console.error('连接错误:', err)
// 重连逻辑
setTimeout(createWebSocket, 3000)
})
// 监听关闭
socketTask.onClose((res) => {
console.log('连接关闭:', res.code, res.reason)
if (res.code !== 1000) {
// 非正常关闭,尝试重连
setTimeout(createWebSocket, 3000)
}
})
return socketTask
}
// 使用
let socket = createWebSocket()
// 页面卸载时关闭连接
onUnload() {
if (socket && socket.readyState === 1) {
socket.close({ code: 1000, reason: '页面卸载' })
}
}
更多推荐


所有评论(0)