You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Django实现XMPP在线好友列表实时更新方案问询

解决Django后端实时推送XMPP好友状态到前端的问题

核心思路

要实现实时推送,需将XMPP监听进程与Django Channels实时通信层打通,让XMPP收到的状态更新通过WebSocket推送到前端页面。


步骤1:正确配置Django Channels

确保Channels基础配置到位,这是实时通信的核心支撑:

  1. 安装依赖:pip install channels channels-redis(用Redis作为通道层后端,稳定性优于内存后端)
  2. 在settings.py中添加配置:
INSTALLED_APPS = [
    # ... 其他已有APP
    'channels',
]

ASGI_APPLICATION = '你的项目名.asgi.application'

CHANNEL_LAYERS = {
    'default': {
        'BACKEND': 'channels_redis.core.RedisChannelLayer',
        'CONFIG': {
            "hosts": [('127.0.0.1', 6379)],
        },
    },
}
  1. 修改项目根目录的asgi.py,替换默认内容:
import os
from django.core.asgi import get_asgi_application
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
import 你的APP名.routing

os.environ.setdefault('DJANGO_SETTINGS_MODULE', '你的项目名.settings')

application = ProtocolTypeRouter({
    "http": get_asgi_application(),
    "websocket": AuthMiddlewareStack(
        URLRouter(
            你的APP名.routing.websocket_urlpatterns
        )
    ),
})

步骤2:编写WebSocket路由与消费者

在你的APP下新建routing.py:

from django.urls import re_path
from . import consumers

websocket_urlpatterns = [
    re_path(r'ws/friend-status/$', consumers.FriendStatusConsumer.as_asgi()),
]

新建consumers.py,实现消息接收与推送逻辑:

from channels.generic.websocket import AsyncWebsocketConsumer
import json

class FriendStatusConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        # 加入统一推送组,方便批量发送状态更新
        self.group_name = 'friend_status_group'
        await self.channel_layer.group_add(
            self.group_name,
            self.channel_name
        )
        await self.accept()

    async def disconnect(self, close_code):
        await self.channel_layer.group_discard(
            self.group_name,
            self.channel_name
        )

    # 定义接收后台推送消息的处理方法
    async def send_status_update(self, event):
        status_data = event['data']
        await self.send(text_data=json.dumps(status_data))

步骤3:改造XMPP监听进程,对接Channels

将XMPP监听逻辑改为Django自定义命令,方便后台运行。在APP的management/commands目录下新建listen_xmpp.py:

import socket
import ssl
import json
from django.core.management.base import BaseCommand
from channels.layers import get_channel_layer
from asgiref.sync import async_to_sync

class Command(BaseCommand):
    help = '监听XMPP服务器的好友状态更新'

    def handle(self, *args, **options):
        hostname = '你的XMPP服务器地址'
        port = 5223  # XMPP默认SSL端口
        # 修正原代码错误:ssl模块调用多了空格,引号需用英文
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1_2)
        sock.connect((hostname, port))

        # 补充XMPP完整握手逻辑:需先发送初始化流、认证信息、绑定资源,再发送presence
        # 示例初始化请求(需根据你的XMPP服务器调整)
        sock.sendall(b"<stream:stream to='你的域名' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>")
        # 此处省略服务器响应接收、认证、绑定等步骤,建议用XMPP库简化开发

        sock.sendall(b"<presence/>")
        channel_layer = get_channel_layer()

        while True:
            response = sock.recv(1024)
            if not response:
                break
            # 解析XMPP presence消息,提取好友状态(建议用slixmpp等库解析,避免手动处理XML)
            # 示例解析后的状态数据
            status_update = {
                'friend_jid': '好友的JID',
                'status': 'online',  # 或'offline'
                'show': 'available'
            }
            # 通过Channels组推送消息到前端
            async_to_sync(channel_layer.group_send)(
                'friend_status_group',
                {
                    'type': 'send_status_update',
                    'data': status_update
                }
            )

提示:直接用socket处理XMPP协议易出错,推荐用slixmpp库,它内置presence监听回调,能大幅简化开发。


步骤4:前端页面实现WebSocket连接与列表更新

在模板页面中添加JavaScript代码,连接WebSocket并实时更新好友列表:

<script>
const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const wsUrl = wsProtocol + '//' + window.location.host + '/ws/friend-status/';
const socket = new WebSocket(wsUrl);

socket.onmessage = function(e) {
    const data = JSON.parse(e.data);
    // 更新好友列表DOM
    const friendItem = document.querySelector(`[data-jid="${data.friend_jid}"]`);
    if (friendItem) {
        if (data.status === 'online') {
            friendItem.classList.add('online');
            friendItem.textContent = `${data.friend_jid} (在线)`;
        } else {
            friendItem.classList.remove('online');
            friendItem.textContent = `${data.friend_jid} (离线)`;
        }
    } else {
        // 新增好友条目
        const list = document.getElementById('friend-list');
        const newItem = document.createElement('li');
        newItem.setAttribute('data-jid', data.friend_jid);
        newItem.textContent = `${data.friend_jid} (${data.status === 'online' ? '在线' : '离线'})`;
        if (data.status === 'online') newItem.classList.add('online');
        list.appendChild(newItem);
    }
};

socket.onclose = function(e) {
    console.error('WebSocket连接关闭,尝试重连...');
    setTimeout(() => window.location.reload(), 3000);
};
</script>

<ul id="friend-list">
    <!-- 初始好友列表由Django视图渲染 -->
    {% for friend in initial_friends %}
    <li data-jid="{{ friend.jid }}" class="{% if friend.status == 'online' %}online{% endif %}">
        {{ friend.jid }} ({% if friend.status == 'online' %}在线{% else %}离线{% endif %})
    </li>
    {% endfor %}
</ul>

运行方式

  1. 启动Redis服务:redis-server
  2. 启动Channels的ASGI服务器:daphne 你的项目名.asgi:application
  3. 启动XMPP监听命令:python manage.py listen_xmpp
  4. (可选)启动Django HTTP服务(处理非实时请求):python manage.py runserver --noreload

内容的提问来源于stack exchange,提问作者Wag

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 18:50:41