pythondjangowebsocketserverdjango-channels

Error in connecting websockets when I push the code to server


I have implemented a Django Channel for real time messages between Group users.

It is working fine on the local system but when I push this to the server, I am getting the error: WebSocket connection to 'ws://nailsent.developmentrecords.com/ws/chat/13/' failed: Error during WebSocket handshake: Unexpected response code: 404 (anonymous) @ 13:465

This is my script

<script>
const currentDate = new Date();
// Get the month abbreviation
const month = new Intl.DateTimeFormat('en-US', { month: 'short' }).format(currentDate);
const day = currentDate.getDate();
const year = currentDate.getFullYear();
let hours = currentDate.getHours();
const ampm = hours >= 12 ? 'p.m.' : 'a.m.';
hours = hours % 12 || 12; // Convert 24-hour to 12-hour format

// Get the minutes
const minutes = currentDate.getMinutes();

// Combine all parts into the desired format
const formattedTime = '${month}. ${day}, ${year}, ${hours}:${minutes} ${ampm}';

    const card = document.querySelector('.card-body');
    const sendMessageInput = document.getElementById('sendMessageInput');
    const sendButton = document.getElementById('sendButton');
    const group_id = "{{ group_id }}";
    const userImg = "{{user_image}}"
    const username = "{{request.user.username}}";

    const chatSocket = new WebSocket('wss://${window.location.host}/ws/chat/${group_id}/');
    chatSocket.onopen = function (event) {
        console.log('WebSocket connection established.');
    };
    document.addEventListener("keydown", (e)=>{
        if (e.keyCode === 13){
            sendMessage();
        }
    })
    // Event listener for send button click
    sendButton.addEventListener('click', sendMessage);
    scrollToBottom();
    // Event listener for incoming messages
    if ("Notification" in window) {
        // Request permission from the user to display notifications
        if (Notification.permission !== "granted") {
            Notification.requestPermission();
        }
    }

    // Function to send a notification
    
    function showCustomNotification(username, message, image) {
    const customNotification = document.getElementById('custom-notification');
    customNotification.querySelector('.username').innerText = username;
    customNotification.querySelector('.message').innerText = message;
    const imageElement = customNotification.querySelector('.image');
    imageElement.src = image; 
    customNotification.style.display = 'block';
    
    // setTimeout(() => {
    //     customNotification.style.display = 'none';
    // }, 5000); // Hides the notification after 5 seconds (adjust as needed)
}

    // Function to append received message to receiver box
    chatSocket.onmessage = function (event) {
        try {
            const data = JSON.parse(event.data);
            if (data.message) {
                // Check if the message is from another user
                if (data.username !== username) {
                    
                    appendReceivedMessage(data.username, data.message, data.image);
                    showCustomNotification(data.username, data.message, data.image)
                }
            }
        } catch (error) {
            console.error('Error processing message:', error);
        }
    };

    // Function to append received message to receiver box
    function appendReceivedMessage(username, message, image) {
        const messageHTML = '<div class="receiver-box">
                            <div class="row">
                                <div class="col-1 d-flex align-items-end">
                                    <img src="${image ? image : "{% static 'all_pages/images/icons/message-def-img.png' %}" }" class="sender-image"
                                   alt="User Image"/>
                                </div>
                                <div class="col-11 ps-3 mb-2">
                                    <div class="ps-2 text-secondary d-block mb-1 text-left"><small>${username}</small></div>
                                    <div class="msg-box received-msg receiver-box1">${message}</div>
                                    <p class="time">${formattedTime}</p>
                                </div>
                            </div>
                        </div>';

        // Create a temporary container element
        const container = document.createElement('div');
        container.classList.add("col-12");
        container.innerHTML = messageHTML;

        // Append the container's child to the desired parent element
        card.appendChild(container);
        scrollToBottom() 
    }

    // Function to send message
    function sendMessage() {
        const message = sendMessageInput.value.trim();
        if (message !== '') {
            appendSentMessage(message);
            chatSocket.send(JSON.stringify({
                'message': message,
                'username': username,
                'group_id': group_id,
                'image': userImg,
            }));
            sendMessageInput.value = '';
        }
    }

    // Function to append sent message to sender box
    function appendSentMessage(message) {
        const messageHTML = '<div class="sender-box">
            <div class="row">
                <div class="col-11 d-flex align-items-end flex-column ps-3 mb-2">
                    <div class="ps-2 text-secondary d-block mb-1 text-right"><small>${username}</small></div>
                    <div class="msg-box sent-msg sender-box1">${message}</div>
                    <p class="time">${formattedTime}</p>
                </div>
                <div class="col-1 d-flex justify-content-end">
                    <div class="d-flex justify-content- align-items-end">
                        <img src=${userImg} class="receiver-image">
                    </div>
                </div>
            </div>
        </div>';

        // Create a temporary container element
        const container = document.createElement('div');
        container.classList.add("col-12");
        container.innerHTML = messageHTML;

        // Append the container's child to the desired parent element
        card.appendChild(container);

     scrollToBottom() 
    }

    function scrollToBottom() {
        card.scrollTop = card.scrollHeight;
    }

</script>

Consumer.py

import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "nailSent_porject.settings")
from channels.layers import get_channel_layer
import django
django.setup()
from channels.generic.websocket import AsyncWebsocketConsumer
import json
from asgiref.sync import sync_to_async
from .models import Message, Group, User
# Now you can access settings like this
class ChatConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        self.group_id = self.scope['url_route']['kwargs']['group_id']
        self.group_name = f'{self.group_id}'
        # Join  group
        await self.channel_layer.group_add(
            self.group_name,
            self.channel_name
        )
        await self.accept()
        url_pattern = self.scope['url_route']['route']
        print(" this is a url=========================", url_pattern)

    async def disconnect(self, close_code):
        # Leave room group
        await self.channel_layer.group_discard(
            self.group_name,
            self.channel_name
        )
    
    async def receive(self, text_data):
        try:
            data = json.loads(text_data)
            message = data['message']
            username = data['username']
            group =  data['group_id']
            image  = data['image']
            # Send message to room group
            await self.save_message(message,username,group)
            await self.channel_layer.group_send(
                self.group_name,
                {
                    'type': 'chat_message',
                    'message': message,
                    'username': username,
                    'image':image,
                }
            )
        except json.JSONDecodeError:
            self.send(data=json.dumps({
                'error': 'Invalid JSON format.'
            }))
        except Exception as e:
            self.send(data=json.dumps({
                'error': str(e)
            }))

    # Receive message from room group
    async def chat_message(self, event):
        try:
            message = event['message']
            username =  event['username']
            image = event['image']
            # sending message to websocket
            await self.send(text_data=json.dumps({
                'message': message,
                'username': username,
                'image':image,
            }))
        except KeyError:
            print("Error: 'message' key not found in event:", event)
        except Exception as e:
            print("Error in chat_message:", e)
    @sync_to_async
    def save_message(self, message,username, group_id):
        user = User.objects.get(username=username)
        group = Group.objects.get(id=group_id)
        Message.objects.create(content=message,sender=user,group=group)

routing.py

from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
from django.urls import re_path
from . import consumers

websocket_urlpatterns = [
    re_path(r'wss/chat/(?P<group_id>[^/]+)/$', consumers.ChatConsumer.as_asgi()),
    ]

application = ProtocolTypeRouter({
    'websocket': AuthMiddlewareStack(
        URLRouter(
            websocket_urlpatterns
        )
    ),
})

I have also created a file with the name of Daphne.socket and daphne.service, however, daphne gets started on the server but gives me the above error.


Solution

  • Try adding /ws/ location to nginx configuration file for your project. For example:

    location /ws/ {
        proxy_pass http://localhost:8000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
    

    In this example websocket connection is in 8000 port