Проблема при соединении веб-сокетов 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 - Я установил
daphne
pip 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]