skip to Main Content

I’ved tried to setup Django with channels to provide notification to React.

https://github.com/axilaris/react-django-channels <– I have put my project code here.

in backend/backend/settings.py

INSTALLED_APPS = [
..
    'channels',
]



CHANNEL_LAYERS = {
    'default': {
        'BACKEND': 'channels.layers.InMemoryChannelLayer'
    }
}

ASGI_APPLICATION = 'backend.routing.application'

in backend/backend/asgi.py

import os
from django.core.asgi import get_asgi_application
from channels.routing import ProtocolTypeRouter, URLRouter
#import backend.routing
import user_api.routing

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings')

application = ProtocolTypeRouter({
    "http": get_asgi_application(),
    "websocket": URLRouter(
        user_api.routing.websocket_urlpatterns
        #backend.routing.websocket_urlpatterns <-- not sure if should be this
    ),
})

in backend/user_api/routing.py

from channels.routing import ProtocolTypeRouter, URLRouter
from django.urls import path
from . import consumers

application = ProtocolTypeRouter({
    "websocket": URLRouter([
        path("ws/notifications/", consumers.NotificationConsumer.as_asgi()),
    ]),
})

in backend/user_api/consumers.py

from channels.generic.websocket import AsyncWebsocketConsumer
import json

class NotificationConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        print "XXX connect"
        await self.accept()

    async def disconnect(self, close_code):
        print "XXX disconnect"
        pass

    async def receive(self, text_data):
        print "XXX receive"
        text_data_json = json.loads(text_data)
        message = text_data_json['message']

        await self.send(text_data=json.dumps({
            'message': message
        }))

Finally in React, App.js

useEffect(() => {

    const ws = new WebSocket('ws://localhost:8000/ws/notification/');

    ws.onopen = () => {
      console.log('Connected to notification websocket');
    };

    ws.onmessage = e => {
      const data = JSON.parse(e.data);
      setMessage(data.message);
    };

    ws.onerror = e => {
      console.error('WebSocket error', e);
    };

    ws.onclose = e => {
      console.error('WebSocket closed', e);
    };

    return () => {
      ws.close();
    };

  }, []);

From the browser console logs, it seems it cannot connect

App.js:59 WebSocket connection to 'ws://localhost:8000/ws/notification/' failed: 
App.js:71 WebSocket error Event
ws.onerror @ App.js:71
App.js:75 WebSocket closed CloseEvent

Note that React is running on port 3000 and Django is on port 8000

% npm start <-- React

% python manage.py runserver <-- Django

logs from django and react https://gist.github.com/axilaris/2e0a5ae1887f7d12a226565efa85dd6f

react logs

App.js:59 WebSocket connection to 'ws://localhost:8000/ws/notification/' failed: 
App.js:71 WebSocket error  Event {isTrusted: true, type: 'error', target: WebSocket, currentTarget: WebSocket, eventPhase: 2, …}
App.js:75 WebSocket closed  CloseEvent {isTrusted: true, wasClean: false, code: 1006, reason: '', type: 'close', …}

django logs

WARNING:django.request:Not Found: /ws/notification/
Not Found: /ws/notification/
WARNING:django.request:Not Found: /ws/notification/
[27/Mar/2024 14:19:44] "GET /ws/notification/ HTTP/1.1" 404 2230
[27/Mar/2024 14:19:44,843] - Broken pipe from ('127.0.0.1', 60943)
[27/Mar/2024 14:19:44] "GET /ws/notification/ HTTP/1.1" 404 2230
[27/Mar/2024 14:19:44,843] - Broken pipe from ('127.0.0.1', 60947)

My feeling is something is missing at Django side that channel is not setup properly and not listening to the connection. What am I missing in my setup.
Some suspect:

  • channel is not called due to channel socket setup is in user_api
  • CORS ?

2

Answers


  1. Problem :-

    Look below.

    application = ProtocolTypeRouter({
        "websocket": URLRouter([
            path("ws/notifications/", consumers.NotificationConsumer.as_asgi()),
        ]),
    })
    

    It’s notifications.

    And

    const ws = new WebSocket('ws://localhost:8000/ws/notification/');
    
    

    It’s notification.

    Path should be same path.

    Use as below.

    Answer :-

    application = ProtocolTypeRouter({
        "websocket": URLRouter([
            path("ws/notifications/", consumers.NotificationConsumer.as_asgi()),
        ]),
    })
    
    

    And

    const ws = new WebSocket('ws://localhost:8000/ws/notifications/');
    
    
    Login or Signup to reply.
  2. The ASGI_APPLICATION should refer to your asgi application correctly use this path:

    ASGI_APPLICATION = "backend/backend/asgi.py"
    

    for better configuration look at django channel documentaion Tutorial:

    Tutorial Part 1: Basic Setup

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search