Django 通道中的 WebSocket 连接失败和意外的套接字关闭

问题描述 投票:0回答:1

我在使用 Django Channels 在 Django 项目中建立和维护 WebSocket 连接时遇到问题。我已经设置了一个通知系统,它使用 WebSockets 向连接的客户端广播消息。但是,我遇到了两个错误:

  1. “与 'ws://127.0.0.1:8000/ws/notification/broadcast/' 的 WebSocket 连接失败”
  2. “聊天套接字意外关闭” 这是我的代码:

路由.py:

from django.urls import re_path  
from . import consumers  
  
websocket_urlpatterns = [  
   re_path(r'ws/notification/(?P<room_name>\w+)/$', consumers.NotificationConsumer.as_asgi()),  
]

views.py:

def notification_view(request):  
   return render(request,'person/notification.html',{'room_name': "broadcast"})

设置.py:

CHANNEL_LAYERS = {  
   'default': {  
      'BACKEND': 'channels_redis.core.RedisChannelLayer',  
      'CONFIG': {  
        "hosts": [('127.0.0.1', 6379)],  
      },  
   },  
}

consumer_context_processor.py:

from notification_app.models import BroadcastNotification  
def notifications(request):  
   allnotifications = BroadcastNotification.objects.all()  
   return {'notifications': allnotifications}

models.py:

class BroadcastNotification(models.Model):  
   message = models.TextField()  
   notification_image=models.ImageField(upload_to="notification",default="notification.jpg",blank=True,null=True)  
   notification_link = models.URLField(max_length=10000, help_text="Add a valid URL",blank=True,null=True)  
   broadcast_on = models.DateTimeField()  
   sent = models.BooleanField(default=False)  
  
   class Meta:  
      ordering = ['-broadcast_on']  
  
@receiver(post_save, sender=BroadcastNotification)  
def notification_handler(sender, instance, created, **kwargs):  
   # call group_send function directly to send notificatoions or you can create a dynamic task in celery beat  
   if created:  
      schedule, created = CrontabSchedule.objects.get_or_create(hour = instance.broadcast_on.hour, minute = instance.broadcast_on.minute, day_of_month = instance.broadcast_on.day, month_of_year = instance.broadcast_on.month)  
      task = PeriodicTask.objects.create(crontab=schedule, name="broadcast-notification-"+str(instance.id), task="notifications_app.tasks.broadcast_notification", args=json.dumps((instance.id,)))

任务.py:

@shared_task(bind = True)  
def broadcast_notification(self, data):  
   print(data)  
   try:  
      notification = BroadcastNotification.objects.filter(id = int(data))  
      if len(notification)>0:  
        notification = notification.first()  
        channel_layer = get_channel_layer()  
        loop = asyncio.new_event_loop()  
        asyncio.set_event_loop(loop)  
        loop.run_until_complete(channel_layer.group_send(  
           "notification_broadcast",  
           {  
              'type': 'send_notification',  
              'message': json.dumps(notification.message),  
           }))  
        notification.sent = True  
        notification.save()  
        return 'Done'  
  
      else:  
        self.update_state(  
           state = 'FAILURE',  
           meta = {'exe': "Not Found"}  
        )  
  
        raise Ignore()  
  
   except:  
      self.update_state(  
           state = 'FAILURE',  
           meta = {  
                'exe': "Failed"  
                # 'exc_type': type(ex).__name__,  
                # 'exc_message': traceback.format_exc().split('\n')  
                # 'custom': '...'  
              }  
        )  
  
      raise Ignore()

前端(JavaScript):

{{ room_name|json_script:"room-name" }}  
   <script>  
      const roomName = JSON.parse(document.getElementById('room-name').textContent);  
  
      const notificationSocket = new WebSocket(  
        'ws://'  
        + window.location.host  
        + '/ws/notification/'  
        + roomName  
        + '/'  
      );  
  
      notificationSocket.onmessage = function(e) {  
        const data = JSON.parse(e.data);  
        //document.querySelector('#chat-log').value += (data.message + '\n');  
        console.log(data);  
        document.getElementById("notifications-dropdown").innerHTML = "<li class='dropdown-item'>" + data + "</li><hr class='dropdown-divider'>" + document.getElementById("notifications-dropdown").innerHTML;  
        document.getElementById("notification-badge").innerHTML = parseInt(document.getElementById("notification-badge").innerHTML) + 1;  
      };  
  
      notificationSocket.onclose = function(e) {  
        console.error('Chat socket closed unexpectedly');  
      };  
   </script>

consumers.py:

class NotificationConsumer(AsyncWebsocketConsumer):  
   async def connect(self):  
      self.room_name = self.scope['url_route']['kwargs']['room_name']  
      self.room_group_name = 'notification_%s' % self.room_name  
  
      # Join room group  
      await self.channel_layer.group_add(  
        self.room_group_name,  
        self.channel_name  
      )  
  
      await self.accept()  
  
   async def disconnect(self, close_code):  
      # Leave room group  
      await self.channel_layer.group_discard(  
        self.room_group_name,  
        self.channel_name  
      )  
  
  
   # Receive message from room group  
   async def send_notification(self, event):  
      message = json.loads(event['message'])  
  
      # Send message to WebSocket  
      await self.send(text_data=json.dumps(message))

我尝试遵循官方 Django Channels 文档和示例,但我仍然面临这些问题。谁能帮我找出问题并提供解决方案?

javascript python django websocket celery
1个回答
0
投票

检查 WebSocket URL 配置 WebSocket 连接失败,并显示:

WebSocket connection to 'ws://127.0.0.1:8000/ws/notification/broadcast/'  
failed
Problem: You're using ws://127.0.0.1:8000/ws/notification/broadcast/, but your routing pattern in routing.py has a regular expression that requires a room_name parameter, so the URL should actually look like:

``
ws://127.0.0.1:8000/ws/notification/broadcast/

这意味着您将 room_name 参数作为 WebSocket URL 的一部分传递,并且它应该与routing.py 中的 URL 模式匹配。这可能会导致 WebSocket 连接失败。

解决方案:确保前端传递的房间名称正确。检查构建 WebSocket URL 时是否传递了正确的 room_name:

const notificationSocket = new WebSocket(
  'ws://' + window.location.host + '/ws/notification/' + roomName + '/'
);

确保 roomName 在前端设置正确,并且它应该与您的routing.py 期望的相匹配。从您当前的代码来看,您可能将 notification_view 上下文中的 room_name 设置为“广播”,这是正确的,但您应该确保它已传递到 WebSocket 连接中。

© www.soinside.com 2019 - 2024. All rights reserved.