skip to Main Content

I’m trying to establish a connection with my Django backend and Flutter code using WebSockets, but unfortunately I’m unable to do so, went through many articles and videos and everyone is basically doing the same without receiving an error.. Please give a little push to, I’m kinda new into this.

First of all I created a new django app called ‘chat_app’ (added it into settings.py), where I created a new model of my Messages:

    class Message(models.Model):
        room = models.ForeignKey(Room, on_delete=models.CASCADE)
        sender = models.ForeignKey(User, on_delete=models.CASCADE)
        content = models.TextField()
        timestamp = models.DateTimeField(auto_now_add=True)
    
        def __str__(self):
            return self.content

Then I made my consumers.py (here I’m a little bit confused, isn’t it better to refer to my room unique_id instead of name, since the ID is unique and not the name in my case? Decided to stick with the tutorial.)

    class ChatConsumer(WebsocketConsumer):
        def connect(self):
            self.room_name = self.scope['url_route']['kwargs']['room_name']
            self.room_group_name = 'chat_%s' % self.room_name
    
            # Join room group
            self.channel_layer.group_add(
                self.room_group_name,
                self.channel_name
            )
    
            self.accept()
    
        def disconnect(self, close_code):
            # Leave room group
            self.channel_layer.group_discard(
                self.room_group_name,
                self.channel_name
            )

Done the routing.py

    # The WebSocket URL pattern for chat rooms is defined by this code
    websocket_urlpatterns = [
        re_path(r'ws/chat_app/(?P<room_name>w+)/$', ChatConsumer.as_asgi()),
    ]

Then added it into my project URLs:

    urlpatterns = [
        path('admin/', admin.site.urls),
        ...,
        path('ws/', include(websocket_urlpatterns)),
    ]

And this is how I’m trying to establish a connection in Flutter, basically it is a new page, where I’m passing room data through the Navigator from the previous page:

class ChatScreen extends StatefulWidget {
  const ChatScreen({
    Key? key,
    required this.room,
  }) : super(key: key);
  final RoomModelResponse room;

  @override
  _ChatScreenState createState() => _ChatScreenState();
}

class _ChatScreenState extends State<ChatScreen> {
  final TextEditingController _controller = TextEditingController();
  final List<String> _messages = [];
  late WebSocketChannel _channel;

  @override
  void initState() {
    super.initState();
    _channel = IOWebSocketChannel.connect(
        'wss://192.168.0.11:8000/ws/chat_app/${widget.room.roomName}/'); // Update the WebSocket URL with your Django server address and room name
    _channel.stream.listen((message) {
      setState(() {
        _messages.add(message);
      });
    });
  }

Outputs:

In the flutter terminal I get the following message:

[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: WebSocketChannelException: WebSocketChannelException: WebSocketException: Connection to 'http://192.168.0.11:8000/ws/chat_app/3wVCio/#' was not upgraded to websocket
#0      new IOWebSocketChannel._withoutSocket.<anonymous closure> (package:web_socket_channel/io.dart:119:24)
#1      Stream.handleError.<anonymous closure> (dart:async/stream.dart:931:16)
#2      _HandleErrorStream._handleError (dart:async/stream_pipe.dart:269:17)
#3      _ForwardingStreamSubscription._handleError (dart:async/stream_pipe.dart:157:13)
#4      _RootZone.runBinaryGuarded (dart:async/zone.dart:1606:10)
#5      _BufferingStreamSubscription._sendError.sendError (dart:async/stream_impl.dart:358:15)
#6      _BufferingStreamSubscription._sendError (dart:async/stream_impl.dart:376:7)
#7      _BufferingStreamSubscription._addError (dart:async/stream_impl.dart:280:7)
#8      _SyncStreamControllerDispatch._sendError (dart:async/stream_controller.dart:788:19)
#9 <…>

Django:

Not Found: /ws/chat_app/3wVCio/
[15/Feb/2024 16:46:19] "GET /ws/chat_app/3wVCio/ HTTP/1.1" 404 4379

Where the "3wVCio" is the unique_id of my room.

I will provide additional information if need

Update:
The latest think I’ve tried is allowing all origin CORS in my project:

INSTALLED_APPS = [
    # other installed apps
    'corsheaders',
]
CORS_ALLOW_ALL_ORIGINS = True

Unfortunately, no success..

Made my ALLOWED_HOST in Django settings to be equal to ['*'] and configured my asgi.py file as follows:

    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings')
    
    application = ProtocolTypeRouter({
        "http": get_asgi_application(),  # Django HTTP ASGI application
        "websocket": OriginValidator(
            AuthMiddlewareStack(
                URLRouter(
                    websocket_urlpatterns
                ),
                ['*']
            )
        ),  # Django Channels WebSocket ASGI application
    })

I tried to handshake with the WebSocket using postman, here is the output:

Error: Unexpected server response: 404
Handshake Details
Request URL: http://192.168.0.11:8000/ws/chat_app/3wVCio/
Request Method: GET
Status Code: 404 Not Found
Request Headers
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: GW/3ZvtVDOXDlKNkIwg2zw==
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
Host: 192.168.0.11:8000
Response Headers
Date: Fri, 16 Feb 2024 15:28:45 GMT
Server: WSGIServer/0.2 CPython/3.12.1
Content-Type: text/html; charset=utf-8
X-Frame-Options: DENY
Content-Length: 4379
X-Content-Type-Options: nosniff
Referrer-Policy: same-origin
Cross-Origin-Opener-Policy: same-origin

2

Answers


  1. Chosen as BEST ANSWER

    What helped me:

    1. I have installed redis using brew - brew install redis
    2. I have started redis, before starting my Django project - redis-server I'm not redis expert, please refer to official redis website
    3. I have installed daphne pip install daphne and added it into my INSTALLED_APPS in settings.py:
        # Application definition
        INSTALLED_APPS = [
            'daphne',
            ...,
        ]
    
    1. I have added ASGI_APPLICATION in settings.py and configured my asgi.py. In settings.py:
        ASGI_APPLICATION = 'project.asgi.application'
    
    1. In asgi.py:
        os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings')
        
        application = ProtocolTypeRouter({
            "http": get_asgi_application(),
            "websocket": AuthMiddlewareStack(
                    URLRouter(
                        websocket_urlpatterns
                    ),
                )
            })
    
    1. I have added CHANNEL_LAYERS like so in settings.py:
        # Configure channel layers
    CHANNEL_LAYERS = {
        'default': {
            'BACKEND': 'channels_redis.core.RedisChannelLayer',
            'CONFIG': {
                'hosts': [('localhost', 6379)],
            },
        },
        'ROUTING': 'ws.routing.application',
    }
    

    And with that, I have finally managed to connect "HANDSHAKE" and "CONNECT" with the WebSocket. I'm sorry, that I cannot give explanation why all of these worked. I just wanted to show, what worked for me.

    WebSocket HANDSHAKING /ws/chat_app/FxmZiA/ [192.168.0.11:60081]

    WebSocket CONNECT /ws/chat_app/FxmZiA/ [192.168.0.11:60081]


  2. in your ChatScreen file there is URL which is quite unusual because there suppose to be only one protocol either wss or http but you are using both so that might be the issue.
    if you want to use web socket then protocol suppose to be only wss or ws.

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