Django+Vue+WebSocket客户端实现问题:数据不展示、仅接收一次如何解决
问题1:数据存入变量但表格不渲染的原因及修复
原因有两点:
- WebSocket 接收到的
event.data是JSON字符串格式,你没有将其转为JavaScript对象,直接赋值给数组类型的signals后,v-for无法正常遍历字符串渲染表格。 - 后端当前返回的是单条对象数据,而
signals定义为数组类型,直接赋值会覆盖数组结构,导致遍历逻辑失效。
修复Vue侧代码,修改getSignals方法里的onmessage回调即可:
this.connection.onmessage = (event) => { // 先把JSON字符串转成JS对象 const newSignal = JSON.parse(event.data) console.log("Successfully retrieved message from websocket", newSignal) // 如果是单条数据需要追加到列表里,用push this.signals.push(newSignal) // 如果是要全量替换列表数据,就赋值为数组格式:this.signals = [newSignal] }
问题2:只能接收一次数据的原因及修复
原因有两点:
- 当前Django的
WSConsumer只在连接建立的connect方法里执行了一次send,后续没有新数据推送的逻辑,自然只能收到一次。 - 前端没有配置WebSocket的异常、断开重连逻辑,连接意外断开后无法自动恢复接收数据。
前端修复:
监听器放在created钩子是合理的,补充异常、断开重连逻辑,同时加组件销毁时关闭连接的逻辑,避免内存泄漏:
export default { name: 'Signals', data() { return { signals: [], connection: null, reconnectTimer: null } }, created() { this.initWebSocket() }, beforeDestroy() { // 组件销毁时关闭连接,清除重连定时器 this.connection.close() if (this.reconnectTimer) clearTimeout(this.reconnectTimer) }, methods: { initWebSocket() { console.log("Starting connection to websocket") this.connection = new WebSocket('ws://localhost:8000/ws/signals/') this.connection.onmessage = (event) => { const newSignal = JSON.parse(event.data) this.signals.push(newSignal) } this.connection.onerror = (err) => { console.error("WebSocket error: ", err) } this.connection.onclose = () => { console.log("WebSocket disconnected, try to reconnect after 3s") // 断开后3s自动重连 this.reconnectTimer = setTimeout(() => { this.initWebSocket() }, 3000) } } } }
后端修复:
如果需要后续主动推送新数据,不能只在connect里发一次,建议用Channels的分组推送功能,示例代码:
import json from channels.generic.websocket import WebsocketConsumer from asgiref.sync import async_to_sync class WSConsumer(WebsocketConsumer): def connect(self): self.accept() # 把当前连接加入signals_group分组 async_to_sync(self.channel_layer.group_add)( "signals_group", self.channel_name ) # 连接建立时的首次推送 self.send(json.dumps({ 'id': 1, 'date': "date", 'marketOpen': "marketOpen", 'symbol': "symbol", 'trade': "trade", 'bias': "bias", 'status': "status" })) # 处理分组推送的消息 def send_signal(self, event): data = event['data'] self.send(json.dumps(data)) def disconnect(self, close_code): # 断开连接时移出分组 async_to_sync(self.channel_layer.group_discard)( "signals_group", self.channel_name )
后续需要推送新数据的地方,调用如下代码即可给所有连接的前端推送:
from channels.layers import get_channel_layer from asgiref.sync import async_to_sync channel_layer = get_channel_layer() async_to_sync(channel_layer.group_send)( "signals_group", { "type": "send.signal", "data": { # 新的信号数据 'id': 2, 'date': "2024-01-01", 'marketOpen': "是", 'symbol': "BTC", 'trade': "做多", 'bias': "多", 'status': "生效中" } } )
额外说明
控制台里的Unchecked runtime.lastError报错是浏览器插件导致的,和你的业务代码无关,可以忽略。
内容的提问来源于stack exchange,提问作者JessicaRyan
相关产品推荐
相关产品推荐

