430 lines
9.8 KiB
JavaScript
430 lines
9.8 KiB
JavaScript
/**
|
||
* 微信小程序 WebSocket 客户端测试代码
|
||
* 用于测试微信小程序环境下与 WebSocket 服务器的连接和通信
|
||
*
|
||
* 使用方法:
|
||
* 1. 将此代码复制到微信小程序的页面 JavaScript 文件中
|
||
* 2. 在对应的 WXML 文件中添加测试按钮和消息显示区域
|
||
* 3. 在微信开发者工具中运行测试
|
||
*/
|
||
|
||
// WebSocket 连接实例
|
||
let ws = null;
|
||
|
||
// 页面数据
|
||
Page({
|
||
data: {
|
||
wsUrl: 'wss://your-domain.com/ws/aikefu', // 替换为你的 WebSocket 服务器地址
|
||
connectionStatus: '未连接',
|
||
messages: [],
|
||
inputMessage: ''
|
||
},
|
||
|
||
// 生命周期函数--监听页面加载
|
||
onLoad: function(options) {
|
||
this.connectWebSocket();
|
||
},
|
||
|
||
// 生命周期函数--监听页面卸载
|
||
onUnload: function() {
|
||
this.closeWebSocket();
|
||
},
|
||
|
||
// 生命周期函数--监听页面隐藏
|
||
onHide: function() {
|
||
this.closeWebSocket();
|
||
},
|
||
|
||
// 连接 WebSocket 服务器
|
||
connectWebSocket: function() {
|
||
const that = this;
|
||
const wsUrl = this.data.wsUrl;
|
||
|
||
// 创建 WebSocket 连接
|
||
ws = wx.connectSocket({
|
||
url: wsUrl,
|
||
header: {
|
||
'content-type': 'application/json'
|
||
},
|
||
method: 'GET',
|
||
success: function(res) {
|
||
console.log('WebSocket 连接请求发送成功', res);
|
||
that.updateStatus('连接中...');
|
||
},
|
||
fail: function(err) {
|
||
console.error('WebSocket 连接请求发送失败', err);
|
||
that.updateStatus('连接失败');
|
||
that.addMessage('系统', 'WebSocket 连接请求发送失败: ' + JSON.stringify(err), 'error');
|
||
}
|
||
});
|
||
|
||
// 监听 WebSocket 连接打开
|
||
ws.onOpen(function(res) {
|
||
console.log('WebSocket 连接已打开', res);
|
||
that.updateStatus('已连接');
|
||
that.addMessage('系统', 'WebSocket 连接已打开', 'system');
|
||
});
|
||
|
||
// 监听 WebSocket 接收到服务器的消息
|
||
ws.onMessage(function(res) {
|
||
console.log('收到服务器消息', res.data);
|
||
that.addMessage('服务器', res.data, 'received');
|
||
});
|
||
|
||
// 监听 WebSocket 连接关闭
|
||
ws.onClose(function(res) {
|
||
console.log('WebSocket 连接已关闭', res);
|
||
that.updateStatus('已断开');
|
||
that.addMessage('系统', 'WebSocket 连接已关闭', 'system');
|
||
});
|
||
|
||
// 监听 WebSocket 错误
|
||
ws.onError(function(res) {
|
||
console.error('WebSocket 连接发生错误', res);
|
||
that.updateStatus('连接错误');
|
||
that.addMessage('系统', 'WebSocket 连接发生错误: ' + JSON.stringify(res), 'error');
|
||
});
|
||
},
|
||
|
||
// 关闭 WebSocket 连接
|
||
closeWebSocket: function() {
|
||
if (ws) {
|
||
wx.closeSocket();
|
||
ws = null;
|
||
}
|
||
},
|
||
|
||
// 发送 Ping 消息
|
||
sendPing: function() {
|
||
this.sendMessage(JSON.stringify({ action: 'ping' }));
|
||
},
|
||
|
||
// 发送测试消息
|
||
sendTestMessage: function() {
|
||
this.sendMessage(JSON.stringify({
|
||
message: '你好,这是微信小程序的测试消息!',
|
||
action: 'test'
|
||
}));
|
||
},
|
||
|
||
// 发送自定义消息
|
||
sendCustomMessage: function() {
|
||
const message = this.data.inputMessage.trim();
|
||
if (!message) {
|
||
wx.showToast({
|
||
title: '请输入消息内容',
|
||
icon: 'none'
|
||
});
|
||
return;
|
||
}
|
||
|
||
try {
|
||
// 尝试解析为 JSON,如果不是 JSON 则包装为 JSON
|
||
JSON.parse(message);
|
||
this.sendMessage(message);
|
||
} catch (error) {
|
||
// 不是 JSON,作为普通文本发送
|
||
this.sendMessage(JSON.stringify({ message: message }));
|
||
}
|
||
|
||
// 清空输入框
|
||
this.setData({
|
||
inputMessage: ''
|
||
});
|
||
},
|
||
|
||
// 发送消息
|
||
sendMessage: function(message) {
|
||
if (!ws) {
|
||
wx.showToast({
|
||
title: 'WebSocket 未连接',
|
||
icon: 'none'
|
||
});
|
||
return;
|
||
}
|
||
|
||
// 检查 WebSocket 连接状态
|
||
wx.getSocketTask().then(task => {
|
||
if (task.readyState === 1) { // 连接已打开
|
||
wx.sendSocketMessage({
|
||
data: message,
|
||
success: () => {
|
||
this.addMessage('我', message, 'sent');
|
||
},
|
||
fail: (err) => {
|
||
console.error('发送消息失败', err);
|
||
this.addMessage('系统', '发送消息失败: ' + JSON.stringify(err), 'error');
|
||
}
|
||
});
|
||
} else {
|
||
wx.showToast({
|
||
title: 'WebSocket 连接未打开',
|
||
icon: 'none'
|
||
});
|
||
this.updateStatus('连接已断开');
|
||
}
|
||
}).catch(err => {
|
||
console.error('获取 SocketTask 失败', err);
|
||
this.updateStatus('连接已断开');
|
||
});
|
||
},
|
||
|
||
// 更新输入框内容
|
||
onInputMessage: function(e) {
|
||
this.setData({
|
||
inputMessage: e.detail.value
|
||
});
|
||
},
|
||
|
||
// 更新连接状态
|
||
updateStatus: function(status) {
|
||
this.setData({
|
||
connectionStatus: status
|
||
});
|
||
},
|
||
|
||
// 添加消息到消息列表
|
||
addMessage: function(sender, content, type) {
|
||
const messages = this.data.messages;
|
||
const now = new Date();
|
||
const time = now.toLocaleTimeString();
|
||
|
||
// 尝试美化 JSON 格式
|
||
let formattedContent = content;
|
||
try {
|
||
const parsed = JSON.parse(content);
|
||
formattedContent = JSON.stringify(parsed, null, 2);
|
||
} catch (error) {
|
||
// 不是 JSON,保持原样
|
||
}
|
||
|
||
messages.push({
|
||
id: Date.now(),
|
||
sender: sender,
|
||
content: formattedContent,
|
||
type: type,
|
||
time: time
|
||
});
|
||
|
||
this.setData({
|
||
messages: messages
|
||
});
|
||
|
||
// 滚动到最新消息
|
||
this.scrollToBottom();
|
||
},
|
||
|
||
// 滚动到消息底部
|
||
scrollToBottom: function() {
|
||
wx.createSelectorQuery().select('#message-list').boundingClientRect(function(rect) {
|
||
if (rect) {
|
||
wx.pageScrollTo({
|
||
scrollTop: rect.height,
|
||
duration: 300
|
||
});
|
||
}
|
||
}).exec();
|
||
},
|
||
|
||
// 重连 WebSocket
|
||
reconnectWebSocket: function() {
|
||
this.closeWebSocket();
|
||
setTimeout(() => {
|
||
this.connectWebSocket();
|
||
}, 1000);
|
||
}
|
||
});
|
||
|
||
// 对应的 WXML 文件示例
|
||
/*
|
||
<view class="container">
|
||
<view class="header">
|
||
<text class="title">WebSocket 测试</text>
|
||
<text class="status {{connectionStatus === '已连接' ? 'connected' : connectionStatus === '连接中...' ? 'connecting' : 'disconnected'}}">
|
||
{{connectionStatus}}
|
||
</text>
|
||
</view>
|
||
|
||
<view class="settings">
|
||
<input class="url-input" placeholder="请输入 WebSocket 服务器地址" value="{{wsUrl}}" bindinput="onInputUrl" />
|
||
<button class="btn" bindtap="connectWebSocket" type="primary" size="mini">连接</button>
|
||
<button class="btn" bindtap="closeWebSocket" type="default" size="mini">断开</button>
|
||
<button class="btn" bindtap="reconnectWebSocket" type="warn" size="mini">重连</button>
|
||
</view>
|
||
|
||
<view class="message-area">
|
||
<scroll-view id="message-list" scroll-y="true" class="message-list">
|
||
<block wx:for="{{messages}}" wx:key="id">
|
||
<view class="message-item {{item.type}}">
|
||
<view class="message-header">
|
||
<text class="sender">{{item.sender}}</text>
|
||
<text class="time">{{item.time}}</text>
|
||
</view>
|
||
<view class="message-content">{{item.content}}</view>
|
||
</view>
|
||
</block>
|
||
</scroll-view>
|
||
</view>
|
||
|
||
<view class="input-area">
|
||
<textarea class="message-input" placeholder="请输入消息..." value="{{inputMessage}}" bindinput="onInputMessage" />
|
||
<view class="btn-group">
|
||
<button class="btn" bindtap="sendPing" type="default" size="mini">发送 Ping</button>
|
||
<button class="btn" bindtap="sendTestMessage" type="default" size="mini">测试消息</button>
|
||
<button class="btn" bindtap="sendCustomMessage" type="primary" size="mini">发送</button>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
*/
|
||
|
||
// 对应的 WXSS 样式文件示例
|
||
/*
|
||
.container {
|
||
display: flex;
|
||
flex-direction: column;
|
||
height: 100vh;
|
||
padding: 20rpx;
|
||
background-color: #f5f5f5;
|
||
}
|
||
|
||
.header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.title {
|
||
font-size: 36rpx;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.status {
|
||
padding: 8rpx 16rpx;
|
||
border-radius: 8rpx;
|
||
font-size: 24rpx;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.status.connected {
|
||
background-color: #d4edda;
|
||
color: #155724;
|
||
}
|
||
|
||
.status.connecting {
|
||
background-color: #fff3cd;
|
||
color: #856404;
|
||
}
|
||
|
||
.status.disconnected {
|
||
background-color: #f8d7da;
|
||
color: #721c24;
|
||
}
|
||
|
||
.settings {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-bottom: 20rpx;
|
||
padding: 20rpx;
|
||
background-color: white;
|
||
border-radius: 10rpx;
|
||
}
|
||
|
||
.url-input {
|
||
flex: 1;
|
||
height: 80rpx;
|
||
padding: 20rpx;
|
||
margin-right: 20rpx;
|
||
border: 1px solid #ddd;
|
||
border-radius: 10rpx;
|
||
font-size: 28rpx;
|
||
}
|
||
|
||
.btn {
|
||
margin-right: 10rpx;
|
||
}
|
||
|
||
.message-area {
|
||
flex: 1;
|
||
margin-bottom: 20rpx;
|
||
background-color: white;
|
||
border-radius: 10rpx;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.message-list {
|
||
height: 100%;
|
||
padding: 20rpx;
|
||
}
|
||
|
||
.message-item {
|
||
margin-bottom: 20rpx;
|
||
padding: 15rpx;
|
||
border-radius: 10rpx;
|
||
max-width: 80%;
|
||
}
|
||
|
||
.message-item.sent {
|
||
align-self: flex-end;
|
||
margin-left: auto;
|
||
background-color: #d4edda;
|
||
border-right: 4rpx solid #28a745;
|
||
}
|
||
|
||
.message-item.received {
|
||
align-self: flex-start;
|
||
background-color: #e9ecef;
|
||
border-left: 4rpx solid #007bff;
|
||
}
|
||
|
||
.message-item.system {
|
||
align-self: center;
|
||
background-color: #fff3cd;
|
||
border-left: 4rpx solid #856404;
|
||
max-width: 90%;
|
||
}
|
||
|
||
.message-item.error {
|
||
align-self: center;
|
||
background-color: #f8d7da;
|
||
border-left: 4rpx solid #dc3545;
|
||
max-width: 90%;
|
||
}
|
||
|
||
.message-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
margin-bottom: 10rpx;
|
||
font-size: 24rpx;
|
||
color: #666;
|
||
}
|
||
|
||
.message-content {
|
||
font-size: 28rpx;
|
||
line-height: 1.5;
|
||
word-break: break-all;
|
||
}
|
||
|
||
.input-area {
|
||
background-color: white;
|
||
padding: 20rpx;
|
||
border-radius: 10rpx;
|
||
}
|
||
|
||
.message-input {
|
||
width: 100%;
|
||
height: 120rpx;
|
||
padding: 20rpx;
|
||
margin-bottom: 20rpx;
|
||
border: 1px solid #ddd;
|
||
border-radius: 10rpx;
|
||
font-size: 28rpx;
|
||
background-color: #f9f9f9;
|
||
}
|
||
|
||
.btn-group {
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
}
|
||
*/
|