websocket断开连接调用失败

c9qzyr3d  于 2021-06-10  发布在  Redis
关注(0)|答案(1)|浏览(488)

我正在跟踪一个turtorial django通道2,我遵循了所有的步骤,我在控制台中有一个失败的连接。我注意到这个问题发生时,我添加通道层设置,当我删除通道层连接成功。如何解决这个问题?
经理

  1. class ThreadManager(models.Manager):
  2. def by_user(self, user):
  3. qlookup = Q(first=user) | Q(second=user)
  4. qlookup2 = Q(first=user) & Q(second=user)
  5. qs = self.get_queryset().filter(qlookup).exclude(qlookup2).distinct()
  6. return qs
  7. def get_or_new(self, user, other_username): # get_or_create
  8. username = user.username
  9. if username == other_username:
  10. return None
  11. qlookup1 = Q(first__username=username) & Q(second__username=other_username)
  12. qlookup2 = Q(first__username=other_username) & Q(second__username=username)
  13. qs = self.get_queryset().filter(qlookup1 | qlookup2).distinct()
  14. if qs.count() == 1:
  15. return qs.first(), False
  16. elif qs.count() > 1:
  17. return qs.order_by('timestamp').first(), False
  18. else:
  19. Klass = user.__class__
  20. user2 = Klass.objects.get(username=other_username)
  21. if user != user2:
  22. obj = self.model(
  23. first=user,
  24. second=user2
  25. )
  26. obj.save()
  27. return obj, True
  28. return None, False

型号.py

  1. class Profile(models.Model):
  2. user = models.OneToOneField(settings.AUTH_USER_MODEL,on_delete=models.CASCADE,blank=True,null=True)
  3. profile_pic = models.ImageField(upload_to='ProfilePicture/', default="ProfilePicture/avatar.png", blank=True)
  4. class Thread(models.Model):
  5. first = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='chat_thread_first')
  6. second = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='chat_thread_second')
  7. updated = models.DateTimeField(auto_now=True)
  8. timestamp = models.DateTimeField(auto_now_add=True)
  9. objects = ThreadManager()
  10. @property
  11. def room_group_name(self):
  12. return f'chat_{self.id}'
  13. def broadcast(self, msg=None):
  14. if msg is not None:
  15. broadcast_msg_to_chat(msg, group_name=self.room_group_name, user='admin')
  16. return True
  17. return False
  18. class ChatMessage(models.Model):
  19. thread = models.ForeignKey(Thread, null=True, blank=True, on_delete=models.SET_NULL)
  20. user = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name='sender', on_delete=models.CASCADE)
  21. message = models.TextField()
  22. timestamp = models.DateTimeField(auto_now_add=True)

视图.py

  1. class InboxView(LoginRequiredMixin, ListView):
  2. template_name = 'inbox.html'
  3. def get_queryset(self):
  4. return Thread.objects.by_user(self.request.user)
  5. class ThreadView(LoginRequiredMixin, FormMixin, DetailView):
  6. template_name = 'thread.html'
  7. form_class = ComposeForm
  8. success_url = './'
  9. def get_queryset(self):
  10. return Thread.objects.by_user(self.request.user)
  11. def get_object(self):
  12. other_username = self.kwargs.get("username")
  13. obj, created = Thread.objects.get_or_new(self.request.user, other_username)
  14. if obj == None:
  15. raise Http404
  16. return obj
  17. def get_context_data(self,**kwargs):
  18. context = super().get_context_data(**kwargs)
  19. context['form'] = self.get_form()
  20. return context
  21. def post(self, request, *args,**kwargs):
  22. if not request.user.is_authenticated:
  23. return HttpResponseForbidden()
  24. self.object = self.get_object()
  25. form = self.get_form()
  26. if form.is_valid():
  27. return self.form_valid(form)
  28. else:
  29. return self.form_invalid(form)
  30. def form_valid(self, form):
  31. thread = self.get_object()
  32. user = self.request.user
  33. message = form.cleaned_data.get("message")
  34. ChatMessage.objects.create(user=user, thread=thread, message=message)
  35. return super().form_valid(form)

网址.py

  1. from django.urls import path
  2. from pixmate.views import (
  3. InboxView,
  4. ThreadView,
  5. )
  6. app_name = 'pixmate'
  7. urlpatterns = [
  8. path("inbox", InboxView.as_view(), name='inbox'),
  9. path('messages/<username>/', ThreadView.as_view(), name='messages'),
  10. ]

asgi.py公司

  1. import os
  2. import django
  3. from channels.routing import get_default_application
  4. os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pixmateDjango.settings")
  5. django.setup()
  6. application = get_default_application()

消费者.py

  1. import asyncio
  2. import json
  3. from django.contrib.auth import get_user_model
  4. from channels.consumer import AsyncConsumer
  5. from channels.db import database_sync_to_async
  6. from pixmate.models import Thread, ChatMessage
  7. from django.db.models import Q
  8. class ChatConsumer(AsyncConsumer):
  9. async def websocket_connect(self, event):
  10. print('connected', event)
  11. other_user = self.scope['url_route']['kwargs']['username']
  12. me = self.scope['user']
  13. thread_obj = await self.get_thread(me, other_user)
  14. self.thread_obj = thread_obj
  15. chat_room = f"thread_{thread_obj.id}"
  16. self.chat_room = chat_room
  17. await self.channel_layer.group_add(
  18. chat_room,
  19. self.channel_name
  20. )
  21. await self.send({
  22. "type": "websocket.accept"
  23. })
  24. async def websocket_receive(self, event):
  25. # when a message is recieved from the websocket
  26. print("receive", event)
  27. front_text = event.get('text', None)
  28. if front_text is not None:
  29. loaded_dict_data = json.loads(front_text)
  30. msg = loaded_dict_data.get('message')
  31. user = self.scope['user']
  32. username = 'default'
  33. if user.is_authenticated:
  34. username = user.username
  35. myResponse = {
  36. 'message': msg,
  37. 'username': username
  38. }
  39. await self.create_chat_message(user, msg)
  40. # broadcasts the message event to be sent, the group send layer
  41. # triggers the chat_message function for all of the group (chat_room)
  42. await self.channel_layer.group_send(
  43. self.chat_room,
  44. {
  45. "type": "chat_message",
  46. "text": json.dumps(myResponse)
  47. }
  48. )
  49. # chat_method is a custom method name that we made
  50. async def chat_message(self, event):
  51. #sends the actual message
  52. await self.send({
  53. "type": "websocket.send",
  54. "text": event['text']
  55. })
  56. async def websocket_disconnect(self, event):
  57. # when the socket disconnects
  58. print('disconnected', event)
  59. @database_sync_to_async
  60. def get_thread(self, user, other_username):
  61. return Thread.objects.get_or_new(user, other_username)[0]
  62. @database_sync_to_async
  63. def create_chat_message(self, me, msg):
  64. thread_obj = self.thread_obj
  65. return ChatMessage.objects.create(thread=thread_obj, user=me, message=msg)

路由.py

  1. from django.urls import path
  2. from channels.routing import ProtocolTypeRouter, URLRouter
  3. from channels.auth import AuthMiddlewareStack
  4. from channels.security.websocket import AllowedHostsOriginValidator, OriginValidator
  5. from pixmate.consumers import ChatConsumer
  6. application = ProtocolTypeRouter({
  7. # Empty for now (http->django views is added by default)
  8. 'websocket': AllowedHostsOriginValidator(
  9. AuthMiddlewareStack(
  10. URLRouter(
  11. [
  12. path('messages/<username>/', ChatConsumer),
  13. ]
  14. )
  15. )
  16. )
  17. })

设置.py

  1. ASGI_APPLICATION = "pixmateDjango.routing.application"
  2. CHANNEL_LAYERS = {
  3. "default": {
  4. "BACKEND": "channels_redis.core.RedisChannelLayer",
  5. "CONFIG": {
  6. "hosts": [("localhost", 6379)],
  7. },
  8. },
  9. }

线程.html

  1. <div class="px-4 py-3 chat-box bg-white" id='chat-items' style="height:435px;">
  2. {% for chat in object.chatmessage_set.all %}
  3. {% if request.user != chat.user %}
  4. <!-- Sender Message-->
  5. <div class="media w-50 mb-3">
  6. <img src="{{ chat.user.profile.profile_pic.url }}" id="avatarImg" width="30" height="30" class="rounded-circle mt-1">
  7. <div class="media-body ml-2">
  8. <div class="bg-light rounded py-2 px-3 mb-2">
  9. <p class="text-small mb-0 text-black">{{ chat.message|emoticons }}</p>
  10. </div>
  11. <p class="small text-muted">
  12. {{ chat.timestamp|date:'M j, Y, g:i a' }}
  13. <i class="fa fa-ellipsis-h float-right"></i>
  14. </p>
  15. </div>
  16. </div>
  17. {% endif %}
  18. {% endfor %}
  19. <form id='form' method='POST' action="." class="chatbox-form">
  20. {% csrf_token %}
  21. {{ form }}
  22. <input = "submit" value="send">
  23. </form>
  24. <!-- Channels Reconnecting Websocket -->
  25. <script src='https://cdnjs.cloudflare.com/ajax/libs/reconnecting-websocket/1.0.0/reconnecting-websocket.js'></script>
  26. <script>
  27. // websocket scripts - client side*
  28. var loc = window.location
  29. var formData = $("#form")
  30. var msgInput = $("#id_message")
  31. var chatHolder = $('#chat-items')
  32. var me = $('#myUsername').val()
  33. var wsStart = 'ws://'
  34. if (loc.protocol == 'https:') {
  35. wsStart = 'wss://'
  36. }
  37. var endpoint = wsStart + loc.host + loc.pathname
  38. var socket = new ReconnectingWebSocket(endpoint)
  39. // below is the message I am receiving
  40. socket.onmessage = function(e) {
  41. console.log("message", e)
  42. var chatDataMsg = JSON.parse(e.data)
  43. var profile_pic = $('#avatarImg').attr("src");
  44. console.log(profile_pic);
  45. //alert(e.data)
  46. if(chatDataMsg.username == me) {
  47. chatHolder.append("<div class='media w-50 ml-auto mb-3'>" + "<div class='media-body'>" + "<div class='bg-primary rounded py-2 px-3 mb-2'>" + "<p class='text-small mb-0 text-white'>" + chatDataMsg.message + "</p>" + "</div>" + "<p class='small text-muted'>" + newMonth + newDate + "<i class='fa fa-ellipsis-h float-right'></i>" + "</p>" + "</div>" + "</div>")
  48. }
  49. else{
  50. chatHolder.append("<div class='media w-50 mb-3'>" + "<img src=" + profile_pic + " width='30' height='30' class='rounded-circle mt-1'/>" + "<div class='media-body ml-2'>" + "<div class='bg-light rounded py-2 px-3 mb-2'>" + "<p class='text-small mb-0 text-black'>" + chatDataMsg.message + "</p>" + "</div>" + "<p class='small text-muted'>" + newMonth + newDate + "<i class='fa fa-ellipsis-h float-right'></i>" + "</p>" + "</div>" + "</div>")
  51. }
  52. }
  53. // below is the message I am sending
  54. socket.onopen = function(e) {
  55. console.log("open", e)
  56. formData.submit(function(event){
  57. event.preventDefault()
  58. var msgText = msgInput.val()
  59. //chatHolder.append("<li>" + msgText + " via " + me + "</li>")
  60. var finalData = {
  61. 'message': msgText
  62. }
  63. socket.send(JSON.stringify(finalData))
  64. formData[0].reset()
  65. })
  66. }
  67. socket.onerror = function(e) {
  68. console.log("error", e)
  69. }
  70. socket.onclose = function(e) {
  71. console.log("close", e)
  72. }
  73. </script>
  74. {% endblock %}
uklbhaso

uklbhaso1#

我找到了解决问题的方法:redis在windows中不支持,所以我安装了memurai,它工作了。

相关问题