如何用Python Flask实现发送消息后无刷新更新对方客户端
实现Flask实时消息推送(类似WhatsApp网页版效果)
要实现接收方无需刷新页面就能获取新消息的效果,核心是改用WebSocket替代传统HTTP请求实现双向实时通信。下面是基于你的现有代码的改造方案:
1. 依赖安装
使用Flask-SocketIO封装WebSocket功能,同时安装异步服务器提升性能:
pip install flask-socketio eventlet
2. 后端配置与改造
初始化SocketIO
在你的Flask应用入口文件中添加SocketIO初始化:
from flask import Flask from flask_socketio import SocketIO, emit, join_room app = Flask(__name__) app.config['SECRET_KEY'] = 'your-existing-secret-key' # 复用你原来的密钥 socketio = SocketIO(app, cors_allowed_origins="*") # 跨域设置根据实际场景调整
改造消息发送接口
保留原有的表单提交逻辑,新增WebSocket推送步骤,将新消息实时推送给接收方:
@views.route('/send-msg/<int:id>', methods=['GET', 'POST']) @login_required def send_msg(id): if request.method == 'POST': message = request.form.get('message') if len(message) < 1: flash('Message is too short!', category='error') else: new_message = Message( data=message, sender_id=current_user.id, receiver_id=id ) db.session.add(new_message) db.session.commit() # 关键:通过SocketIO推送给目标用户 socketio.emit( 'new_message', { 'sender_id': current_user.id, 'content': message, 'timestamp': new_message.timestamp.strftime('%Y-%m-%d %H:%M:%S') }, room=f'user_{id}' # 推送给接收方的专属房间 ) flash('Message sent!', category='success') return render_template( "message_sender.html", user=current_user, to_contact=Contact.query.get(id) )
添加房间监听逻辑
在后端添加用户加入房间的事件处理,确保用户进入聊天页面后能接收专属推送:
@socketio.on('join_room') def handle_join_room(room): join_room(room)
3. 前端页面改造(message_sender.html)
引入SocketIO客户端库
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js"></script>
(若禁止外链,可将JS文件下载到本地项目中引入)
添加实时消息处理逻辑
在页面中添加以下脚本,实现SocketIO连接、房间加入、新消息监听与DOM更新:
<script type="text/javascript"> document.addEventListener('DOMContentLoaded', function() { // 初始化SocketIO连接 const socket = io(); const currentUserId = {{ user.id }}; // 加入当前用户的专属房间,接收发给自己的消息 socket.emit('join_room', `user_${currentUserId}`); // 监听新消息事件,动态更新页面 socket.on('new_message', function(msgData) { const messageContainer = document.getElementById('message-container'); const newMessage = document.createElement('div'); // 根据自己的CSS样式调整类名 newMessage.className = 'message received'; newMessage.innerHTML = ` <div class="msg-sender">用户${msgData.sender_id}</div> <div class="msg-content">${msgData.content}</div> <div class="msg-time">${msgData.timestamp}</div> `; messageContainer.appendChild(newMessage); // 自动滚动到最新消息 messageContainer.scrollTop = messageContainer.scrollHeight; }); // 拦截表单提交,用AJAX发送避免页面刷新 const sendForm = document.getElementById('send-form'); sendForm.addEventListener('submit', function(e) { e.preventDefault(); const msgInput = document.getElementById('msg-input'); const message = msgInput.value.trim(); if (!message) return; // 发送消息到后端 fetch(`/send-msg/{{ to_contact.id }}`, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: `message=${encodeURIComponent(message)}` }).then(() => { // 自己发送的消息立即显示到页面 const messageContainer = document.getElementById('message-container'); const sentMsg = document.createElement('div'); sentMsg.className = 'message sent'; sentMsg.innerHTML = ` <div class="msg-content">${message}</div> <div class="msg-time">${new Date().toLocaleString()}</div> `; messageContainer.appendChild(sentMsg); messageContainer.scrollTop = messageContainer.scrollHeight; msgInput.value = ''; }); }); }); </script>
注意:需确保页面中的消息容器有message-container ID,表单有send-form ID,输入框有msg-input ID,同时根据你的CSS样式调整消息元素的类名。
4. 启动应用
将原来的app.run()替换为SocketIO的启动方式:
if __name__ == '__main__': socketio.run(app, debug=True)
核心逻辑说明
- 房间机制:每个用户对应一个专属房间(如
user_123),后端通过房间精准推送消息给目标用户。 - 双向通信:WebSocket建立后,后端可主动向客户端推送消息,无需客户端轮询。
- 消息持久化:保留原有的数据库存储逻辑,确保刷新页面后历史消息不丢失。
内容的提问来源于stack exchange,提问作者Asher Brownstein
相关产品推荐
相关产品推荐

