КАНАЛЫ DJANGO
Я пытаюсь заставить каналы django работать с daphne, но я не могу подключить комнаты, приложение работает хорошо, но всякий раз, когда я запускаю приложение и открываю вебсокет "комнаты", он автоматически отключается, стоит упомянуть, что мой сайт работает с HTTP, и любая помощь будет оценена по достоинству
У меня есть
Django==4.0.6
daphne==3.0.2
channels==3.0.5
Мои конфигурации
ASGI.PY
import os
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.security.websocket import AllowedHostsOriginValidator
from django.core.asgi import get_asgi_application
from django.urls import path
import django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myProject.settings")
# Initialize Django ASGI application early to ensure the AppRegistry
# is populated before importing code that may import ORM models.
django.setup()
django_asgi_app = get_asgi_application()
from chat import consumers
application = ProtocolTypeRouter({
# Django's ASGI application to handle traditional HTTP requests
"http": django_asgi_app,
# WebSocket chat handler
"websocket": AllowedHostsOriginValidator(
AuthMiddlewareStack(
URLRouter([
path("ws/<str:room_name>/", consumers.ChatConsumer.as_asgi()),
])
)
),
})
ПРОКФИЛЬ (работает Дафна)
web: daphne myProject.asgi:application --port $PORT --bind 0.0.0.0 -v2
web2: gunicorn myProject.wsgi --log-file -
worker: python manage.py runworker channel_layer -v2
НАСТРОЙКИ
....
ASGI_APPLICATION = 'myProject.asgi.application'
# Channels
CHANNEL_LAYERS = {
"default": {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
"CONFIG": {
"hosts": ["redis://:XXXXXXXXXXXeca8e639d8b1ca9617d708224c89641133e6191292a@XXXXXXXXX-25-163.compute-1.amazonaws.com:27320"]
},
},
}
....
CONSUMERS.PY
import json
from channels.generic.websocket import AsyncWebsocketConsumer
from asgiref.sync import sync_to_async
from django.contrib.auth.models import User
from .models import Message, Room
class ChatConsumer(AsyncWebsocketConsumer):
async def connect(self):
self.room_name = self.scope['url_route']['kwargs']['room_name'] # url route {'args': (), 'kwargs': {'room_name': 'Yoru Room Name'}}
self.room_group_name = 'chat_%s' % self.room_name #chat_my_room
await self.channel_layer.group_add(
self.room_group_name, # group
self.channel_name # channel
)
await self.accept()
async def disconnect(self, close_code):
await self.channel_layer.group_discard(
self.room_group_name, # group
self.channel_name # channel
)
async def receive(self, text_data):
data = json.loads(text_data) # load json package {"message":"","username":"","room":""}
message = data['message']
username = data['username']
room = data['room']
await self.save_message(username, room, message)
await self.channel_layer.group_send(
self.room_group_name,
{
'type' : 'chat_message',
'message' : message,
'username' : username,
'room' : room,
}
)
async def chat_message(self, event):
message = event['message']
username = event['username']
room = event['room']
await self.send(text_data=json.dumps({ # create json package {"message":"","username":"","room":""}
'message' : message,
'username' : username,
'room' : room,
}))
@sync_to_async
def save_message(self, username, room, message):
user = User.objects.get(username=username)
room = Room.objects.get(slug=room)
Message.objects.create(user=user, room=room, content=message)
ROOM.HTML
{{ room.slug|json_script:"json-roomname" }}
{{request.user.username|json_script:"json-username"}}
<script>
const roomName = JSON.parse(document.getElementById('json-roomname').textContent);
const userName = JSON.parse(document.getElementById('json-username').textContent);
const charSocket = new WebSocket(
(window.location.protocol === 'https:' ? 'wss' : 'ws') + '://'
+ window.location.host
+ '/ws/'
+ roomName
+ '/'
);
Я вижу, что вы жестко закодировали REDIS_URL
в конфигурации CHANNEL_LAYER
.
Если экземпляр REDIS, который вы используете, получен от heroku add-ons, лучше всего получить к нему доступ из переменной окружения. Вы захотите сделать это, потому что учетные данные heroku add-ons часто меняются время от времени.
Прочитайте эту документацию Heroku об изменении учетных данных дополнений здесь
Стоит отметить, что хранение учетных данных во внешнем хранилище также является хорошей практикой. Поступая таким образом, вы следуете двенадцатифакторной методологии приложений.
Также тот факт, что вы работаете на http, не вызвал проблему, так как вы хорошо справились с этим, используя протокол 'ws' при работе на http (см. оператор ternary при установке соединения websocket).
Согласно ответу @FAYEMI BOLUWATIFE Я изменил слой Channel и это сработало!
CHANNEL_LAYERS = {
"default": {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
"CONFIG": {
"hosts": [os.environ.get('REDIS_URL')]
},
},
}