Проблема при соединении веб-сокетов 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.
Что мне помогло:
- Я установил redis, используя
brew-brew install redis - Я запустил redis, прежде чем начать мой проект Django -
redis-serverЯ не эксперт по redis, пожалуйста, обратитесь к официальному сайту redis - Я установил
daphnepip install daphneи добавил его в мойINSTALLED_APPSв settings.py:
# Application definition
INSTALLED_APPS = [
'daphne',
...,
]
- Я добавил
ASGI_APPLICATIONвsettings.pyи настроилasgi.py. Вsettings.py:
ASGI_APPLICATION = 'project.asgi.application'
- В
asgi.py:
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings')
application = ProtocolTypeRouter({
"http": get_asgi_application(),
"websocket": AuthMiddlewareStack(
URLRouter(
websocket_urlpatterns
),
)
})
- Я добавил
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]