Проблема при соединении веб-сокетов Django и Flutter

Я пытаюсь установить соединение с моим бэкендом Django и кодом Flutter, используя WebSockets, но, к сожалению, у меня не получается, просмотрел много статей и видео, и все в основном делают то же самое, не получая ошибок. Пожалуйста, дайте небольшой толчок, я вроде как новичок в этом.

Сначала я создал новое приложение django под названием 'chat_app' (добавил его в settings.py), где я создал новую модель моего 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

Затем я сделал свою consumers.py (тут я немного запутался, не лучше ли называть комнату unique_id вместо имени, ведь ID уникален, а не имя в моем случае? Решил придерживаться учебника.)

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
        )

Выполнено 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()),
]

Затем добавил его в URL-адреса моего проекта:

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

Вот как я пытаюсь установить соединение во Flutter, в основном это новая страница, на которой я передаю данные комнаты через Navigator с предыдущей страницы:

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://http://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);
      });
    });
  }

Выходы:

В терминале flutter я получаю следующее сообщение:

[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

Где "3wVCio" - это unique_id моей комнаты.

При необходимости я предоставлю дополнительную информацию

в вашем файле ChatScreen есть URL, что довольно необычно, потому что должен быть только один протокол либо wss, либо http, но вы используете оба, так что это может быть проблемой. Если вы хотите использовать веб-сокет, то протокол должен быть только wss or ws.

Что мне помогло:

  1. Я установил redis, используя brew - brew install redis
  2. Я запустил redis, прежде чем начать мой проект Django - redis-server Я не эксперт по redis, пожалуйста, обратитесь к официальному сайту redis
  3. Я установил daphne pip install daphne и добавил его в мой INSTALLED_APPS в settings.py:
    # Application definition
    INSTALLED_APPS = [
        'daphne',
        ...,
    ]
  1. Я добавил ASGI_APPLICATION в settings.py и настроил asgi.py. В settings.py:
    ASGI_APPLICATION = 'project.asgi.application'
  1. В asgi.py:
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings')
    
    application = ProtocolTypeRouter({
        "http": get_asgi_application(),
        "websocket": AuthMiddlewareStack(
                URLRouter(
                    websocket_urlpatterns
                ),
            )
        })
  1. Я добавил CHANNEL_LAYERS так в settings.py:
    # Configure channel layers
CHANNEL_LAYERS = {
    'default': {
        'BACKEND': 'channels_redis.core.RedisChannelLayer',
        'CONFIG': {
            'hosts': [('localhost', 6379)],
        },
    },
    'ROUTING': 'ws.routing.application',
}

И вот, наконец, мне удалось соединить "HANDSHAKE" и "CONNECT" с WebSocket. Извините, но я не могу объяснить, почему все это сработало. Я просто хотел показать, что сработало у меня.

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

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

Вернуться на верх