test_websocket_fix.js 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. /**
  2. * WebSocket 修复验证测试脚本
  3. *
  4. * 这个脚本模拟了我们在 living.vue 中所做的修复,
  5. * 用于验证修复逻辑的正确性
  6. */
  7. // 模拟 uni-app 的 WebSocket API
  8. const mockUniApp = {
  9. connectSocket: (options) => {
  10. console.log('🔌 模拟连接 WebSocket:', options.url);
  11. // 模拟 socketTask 对象
  12. const socketTask = {
  13. readyState: 0, // CONNECTING
  14. onOpen: null,
  15. onClose: null,
  16. onError: null,
  17. onMessage: null,
  18. send: (data) => {
  19. if (socketTask.readyState === 1) {
  20. console.log('📤 发送消息:', data.data);
  21. return Promise.resolve();
  22. } else {
  23. console.log('❌ 连接未就绪,无法发送消息');
  24. return Promise.reject(new Error('WebSocket not ready'));
  25. }
  26. },
  27. close: () => {
  28. socketTask.readyState = 3; // CLOSED
  29. console.log('🔌 WebSocket 连接已关闭');
  30. }
  31. };
  32. // 模拟连接过程
  33. setTimeout(() => {
  34. socketTask.readyState = 1; // OPEN
  35. if (socketTask.onOpen) {
  36. console.log('✅ WebSocket 连接成功');
  37. socketTask.onOpen();
  38. }
  39. }, 1000);
  40. return socketTask;
  41. }
  42. };
  43. // 模拟 living.vue 中的相关状态和方法
  44. class MockLivingComponent {
  45. constructor() {
  46. this.socket = null;
  47. this.isSocketOpen = false;
  48. this.isConnecting = false;
  49. this.isSending = false;
  50. this.retryCount = 0;
  51. this.maxRetries = 3;
  52. this.liveId = 'test_live_123';
  53. this.userData = { userId: 'user_123', nickname: 'TestUser' };
  54. }
  55. // 修复后的 initSocket 方法
  56. initSocket() {
  57. console.log('\n🚀 开始初始化 WebSocket 连接...');
  58. if (this.isConnecting) {
  59. console.log('⚠️ 正在连接中,跳过重复连接');
  60. return;
  61. }
  62. this.isConnecting = true;
  63. this.isSocketOpen = false;
  64. const socketTask = mockUniApp.connectSocket({
  65. url: `wss://example.com/websocket?liveId=${this.liveId}`
  66. });
  67. // 🔧 修复:立即赋值 socket,而不是等到 onOpen
  68. this.socket = socketTask;
  69. console.log('✅ socket 实例已赋值');
  70. socketTask.onOpen = () => {
  71. console.log('📡 WebSocket onOpen 事件触发');
  72. this.isConnecting = false;
  73. this.isSocketOpen = true;
  74. this.retryCount = 0;
  75. console.log('🎉 WebSocket 连接建立完成');
  76. };
  77. socketTask.onClose = () => {
  78. console.log('🔌 WebSocket onClose 事件触发');
  79. this.isSocketOpen = false;
  80. this.isConnecting = false;
  81. };
  82. socketTask.onError = (error) => {
  83. console.log('❌ WebSocket onError 事件触发:', error);
  84. this.isSocketOpen = false;
  85. this.isConnecting = false;
  86. };
  87. }
  88. // 修复后的 isSocketAvailable 方法
  89. isSocketAvailable() {
  90. const hasSocket = !!this.socket;
  91. const isOpen = this.isSocketOpen;
  92. const readyState = this.socket ? this.socket.readyState : -1;
  93. console.log('🔍 检查 WebSocket 状态:', {
  94. hasSocket,
  95. isOpen,
  96. readyState,
  97. readyStateText: this.getReadyStateText(readyState)
  98. });
  99. return hasSocket && isOpen && this.socket.readyState === 1;
  100. }
  101. getReadyStateText(state) {
  102. const states = {
  103. 0: 'CONNECTING',
  104. 1: 'OPEN',
  105. 2: 'CLOSING',
  106. 3: 'CLOSED',
  107. '-1': 'UNDEFINED'
  108. };
  109. return states[state] || 'UNKNOWN';
  110. }
  111. // 修复后的 sendMsg 方法(简化版)
  112. async sendMsg(message) {
  113. console.log(`\n📝 尝试发送消息: "${message}"`);
  114. if (this.isSending) {
  115. console.log('⚠️ 正在发送中,防止重复发送');
  116. return;
  117. }
  118. if (!message || message.trim() === '') {
  119. console.log('❌ 消息内容为空');
  120. return;
  121. }
  122. if (!this.liveId || !this.userData) {
  123. console.log('❌ 缺少必要参数 liveId 或 userData');
  124. return;
  125. }
  126. this.isSending = true;
  127. try {
  128. // 检查连接状态
  129. if (!this.isSocketAvailable()) {
  130. console.log('⚠️ WebSocket 连接不可用');
  131. if (this.isConnecting) {
  132. console.log('⏳ 正在连接中,等待连接完成...');
  133. // 在实际应用中,这里会等待连接完成
  134. await this.waitForConnection();
  135. } else {
  136. console.log('🔄 尝试重新连接...');
  137. this.initSocket();
  138. await this.waitForConnection();
  139. }
  140. }
  141. // 再次检查连接状态
  142. if (!this.isSocketAvailable()) {
  143. throw new Error('WebSocket 连接失败');
  144. }
  145. // 发送消息
  146. const messageData = {
  147. type: 'message',
  148. content: message,
  149. liveId: this.liveId,
  150. user: this.userData,
  151. timestamp: Date.now()
  152. };
  153. await this.socket.send({
  154. data: JSON.stringify(messageData)
  155. });
  156. console.log('✅ 消息发送成功');
  157. } catch (error) {
  158. console.log('❌ 消息发送失败:', error.message);
  159. if (this.retryCount < this.maxRetries) {
  160. this.retryCount++;
  161. console.log(`🔄 准备重试 (${this.retryCount}/${this.maxRetries})`);
  162. setTimeout(() => {
  163. this.sendMsg(message);
  164. }, 800);
  165. } else {
  166. console.log('💥 重试次数用尽,发送失败');
  167. }
  168. } finally {
  169. this.isSending = false;
  170. }
  171. }
  172. // 等待连接完成的辅助方法
  173. waitForConnection(timeout = 5000) {
  174. return new Promise((resolve, reject) => {
  175. const startTime = Date.now();
  176. const checkConnection = () => {
  177. if (this.isSocketAvailable()) {
  178. resolve();
  179. } else if (Date.now() - startTime > timeout) {
  180. reject(new Error('连接超时'));
  181. } else {
  182. setTimeout(checkConnection, 100);
  183. }
  184. };
  185. checkConnection();
  186. });
  187. }
  188. }
  189. // 运行测试
  190. async function runTest() {
  191. console.log('🧪 开始 WebSocket 修复验证测试\n');
  192. const component = new MockLivingComponent();
  193. // 测试场景1:在连接建立前尝试发送消息
  194. console.log('📋 测试场景1:连接建立前发送消息');
  195. component.sendMsg('Hello, this is a test message!');
  196. // 等待一段时间让连接建立
  197. setTimeout(() => {
  198. console.log('\n📋 测试场景2:连接建立后发送消息');
  199. component.sendMsg('Second message after connection established');
  200. }, 2000);
  201. // 测试连续发送
  202. setTimeout(() => {
  203. console.log('\n📋 测试场景3:连续发送多条消息');
  204. component.sendMsg('Message 1');
  205. component.sendMsg('Message 2');
  206. component.sendMsg('Message 3');
  207. }, 3000);
  208. }
  209. // 启动测试
  210. runTest();
  211. console.log(`
  212. 📊 测试说明:
  213. =============
  214. 1. 这个测试模拟了我们在 living.vue 中所做的关键修复
  215. 2. 主要验证点:
  216. - socket 实例在 connectSocket 后立即可用
  217. - isSocketAvailable 方法能正确判断连接状态
  218. - sendMsg 方法在连接未就绪时能正确处理
  219. - 防重复发送机制正常工作
  220. - 重试机制正常工作
  221. 🔧 关键修复点:
  222. ==============
  223. - 将 this.socket = socketTask 从 onOpen 事件中提前到 connectSocket 之后
  224. - 增强了 isSocketAvailable 方法的状态检查
  225. - 优化了 sendMsg 方法的错误处理和重试逻辑
  226. `);