Daphne Nginx Gunicorn Rdis Django WebSocket通信の方法
解決したいこと
Websocketの接続
例)
Djangoでリアルタイムチャット機能がついたアプリを開発しています。
チャット機能の実装中に以下のエラーが発生してしまいました。
systemctl status の結果は全て正常です。
解決方法を教えて下さい。
正直コピーアンドペーストでやってきたものなので何が何だかわからない状態です。皆さんの力を貸してください!!!
発生している問題・エラー
ブラウザのコンソール
WebSocket connection to 'wss://finalclub.link/ws/dm/3/' failed:
Nginx configファイル
# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
upstream channels-backend {
server localhost:8001;
}
client_max_body_size 100M;
server {
listen 80;
listen [::]:80;
server_name finalclub.link;
return 301 https://$host$request_uri;
location / {
proxy_pass http://unix:/root/FinalClub.sock;
}
location /ws/ {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_redirect off;
proxy_pass http://unix:/tmp/daphne.sock;
}
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name finalclub.link;
root /usr/share/nginx/html;
client_max_body_size 100M;
client_body_buffer_size 100M;
ssl_certificate "/etc/letsencrypt/live/finalclub.link/fullchain.pem";
ssl_certificate_key "/etc/letsencrypt/live/finalclub.link/privkey.pem";
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
56,10-24 6%
Gunicorn.serviceファイル
[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target
[Service]
User=root
Group=root
WorkingDirectory=/root/FinalClub
ExecStart=/root/venv/bin/gunicorn --access-logfile /var/log/django --workers 3 --bind unix:/run/gunicorn.sock FinalClub.wsgi:application
[Install]
WantedBy=multi-user.target
Daphne.serviceファイル
[Unit]
Description=WebSocket Daphne Service
After=network.target
[Service]
User=root
Group=root
WorkingDirectory=/root/FinalClub
ExecStart=/root/venv/bin/daphne -u /tmp/daphne.sock FinalClub.asgi:application
Restart=on-failure
[Install]
WantedBy=multi-user.target
asgi.py
import os
import django
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'FinalClub.settings')
django.setup()
from django.core.asgi import get_asgi_application
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.security.websocket import AllowedHostsOriginValidator
from chat.routing import websocket_urlpatterns
application = ProtocolTypeRouter({
'http': get_asgi_application(),
'websocket': AllowedHostsOriginValidator(
AuthMiddlewareStack((
URLRouter(
websocket_urlpatterns
)
))
)
})
settings.py
...
ASGI_APPLICATION = 'FinalClub.asgi.application'
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': { 'hosts': [('finalclub.link', 6379)], },
},
}
...
chat.routing.py
from django.urls import path
from . import consumers
websocket_urlpatterns = [
path( 'ws/<str:room_id>/', consumers.ChatConsumer.as_asgi() ),
path('ws/dm/<str:dm_id>/', consumers.DmConsumer.as_asgi()),
chat.comsumers.py
from datetime import datetime
import json
from django.contrib.auth.models import User
from channels.generic.websocket import AsyncWebsocketConsumer
from asgiref.sync import sync_to_async
from .models import Room, Message, DMBox, DMMessages
from sns.models import Users, UserProfiles
class ChatConsumer(AsyncWebsocketConsumer):
async def connect(self):
self.room_name = self.scope['url_route']['kwargs']['room_id']
self.room_group_name = 'chat_%s' % self.room_name
print(self.room_name)
print(self.room_group_name)
await self.channel_layer.group_add(
self.room_group_name,
self.channel_name
)
await self.accept()
async def disconnect(self):
await self.channel_layer.group_discard(
self.room_group_name,
self.channel_name
)
# Receive message from WebSocket
async def receive(self, text_data):
data = json.loads(text_data)
message = data['message']
username = data['username']
room = data['room']
await self.save_message(username, room, message)
user_icon, user_url = await self.get_user_icon_url(username)
# Send message to room group
await self.channel_layer.group_send(
self.room_group_name,
{
'type': 'chat_message',
'message': message,
'username': username,
'user_icon': user_icon,
'user_url': user_url
}
)
# Receive message from room group
async def chat_message(self, event):
print(event)
message = event['message']
username = event['username']
user_icon = event['user_icon']
user_url = event['user_url']
# Send message to WebSocket
await self.send(text_data=json.dumps({
'message': message,
'username': username,
'user_icon': user_icon,
'user_url': user_url
}))
@sync_to_async
def save_message(self, username, room, message):
user = UserProfiles.objects.get(username=username).user
room = Room.objects.get(id=room)
Message.objects.create(user=user, room=room, content=message)
@sync_to_async
def get_user_icon_url(self, username):
user_profile = UserProfiles.objects.get(username=username)
user_icon = user_profile.user_icon.url
user_url = f'/user_home/{ user_profile.username }/'
return user_icon, user_url
class DmConsumer(AsyncWebsocketConsumer):
async def connect(self):
self.room_name = self.scope['url_route']['kwargs']['dm_id']
self.room_group_name = 'chat_%s' % self.room_name
print(self.room_name)
print(self.room_group_name)
await self.channel_layer.group_add(
self.room_group_name,
self.channel_name
)
await self.accept()
async def disconnect(self):
await self.channel_layer.group_discard(
self.room_group_name,
self.channel_name
)
# Receive message from WebSocket
async def receive(self, text_data):
data = json.loads(text_data)
message = data['message']
username = data['username']
dm_id = data['dm']
await self.save_message(username, dm_id, message)
user_icon, user_url = await self.get_user_icon_url(username)
# Send message to room group
await self.channel_layer.group_send(
self.room_group_name,
{
'type': 'chat_message',
'message': message,
'username': username,
'user_icon': user_icon,
'user_url': user_url
}
)
# Receive message from room group
async def chat_message(self, event):
print(event)
message = event['message']
username = event['username']
user_icon = event['user_icon']
user_url = event['user_url']
# Send message to WebSocket
await self.send(text_data=json.dumps({
'message': message,
'username': username,
'user_icon': user_icon,
'user_url': user_url
}))
@sync_to_async
def save_message(self, username, dm_id, message):
user = UserProfiles.objects.get(username=username).user
dm_box = DMBox.objects.get(id=dm_id)
dm_box.time = datetime.now()
dm_box.save()
DMMessages.objects.create(dm_box=dm_box, user=user, message=message)
@sync_to_async
def get_user_icon_url(self, username):
user_profile = UserProfiles.objects.get(username=username)
user_icon = user_profile.user_icon.url
user_url = f'/user_home/{ user_profile.username }/'
return user_icon, user_url
該当javascript
/* jshint esversion: 6 */
/* jshint node: true */
window.addEventListener('DOMContentLoaded', function(){
"use strict";
var windowHeightSize = $(window).height();
var windowWidthSize = $(window).width();
var message_height = windowHeightSize - 155;
var chat_messages = document.getElementById('chat-messages');
if (windowWidthSize <= 700) {
chat_messages.style.height = message_height + 'px';
}
const DmId = JSON.parse(document.getElementById('json-dmid').textContent);
const userName = JSON.parse(document.getElementById('json-username').textContent);
const chatSocket = new WebSocket(
'wss://'
+ window.location.host
+ '/ws/dm/'
+ DmId
+ '/'
);
chatSocket.onclose = function(e) {
console.log('onclose')
}
chatSocket.onmessage = function(e) {
const data = JSON.parse(e.data);
if (data.message) {
var chat_middle_wrap = document.querySelector('.chat-middle-wrap');
if (data.username == userName) {
var message_wrap = document.createElement('div')
message_wrap.className = 'message-wrap'
var message_text_container_right = document.createElement('div')
message_text_container_right.className = 'message-text-container right'
message_wrap.insertBefore(message_text_container_right, null)
var message_text_wrap = document.createElement('div')
message_text_wrap.className = 'message-text-wrap'
message_text_container_right.insertBefore(message_text_wrap, null)
var message_text = document.createElement('div')
message_text.className = 'message-text'
message_text.innerText = data.message
message_text_wrap.insertBefore(message_text, null)
var balloon_right = document.createElement('div')
balloon_right.className = 'balloon right'
message_wrap.appendChild(balloon_right)
chat_middle_wrap.appendChild(message_wrap)
} else {
var message_container = document.createElement('div')
message_container.className = 'message-container'
var message_wrap = document.createElement('div')
message_wrap.className = 'message-wrap'
message_container.insertBefore(message_wrap, null)
var message_user_icon_container = document.createElement('div')
message_user_icon_container.className = 'message-user-icon-container'
message_wrap.appendChild(message_user_icon_container)
var message_user_icon = document.createElement('div')
message_user_icon.className = 'message-user-icon'
var user_icon = document.createElement('img')
user_icon.src = data.user_icon
message_user_icon.insertBefore(user_icon, null)
message_user_icon_container.insertBefore(message_user_icon, null)
var message_user_info_container = document.createElement('div')
message_user_info_container.className = 'message-user-info-container'
message_wrap.appendChild(message_user_info_container)
var message_username_container = document.createElement('div')
message_username_container.className = 'message-username-container'
message_user_info_container.appendChild(message_username_container)
var message_username = document.createElement('div')
message_username.className = 'message-username'
message_username.innerText = data.username
message_username_container.appendChild(message_username)
var message_text_container = document.createElement('div')
message_text_container.className = 'message-text-container'
message_user_info_container.appendChild(message_text_container)
var message_text_wrap = document.createElement('div')
message_text_wrap.className = 'message-text-wrap'
message_text_container.appendChild(message_text_wrap)
var message_text = document.createElement('div')
message_text.className = 'message-text'
message_text.innerText = data.message
message_text_wrap.appendChild(message_text)
var balloon = document.createElement('div')
balloon.className = 'balloon'
message_text_container.appendChild(balloon)
chat_middle_wrap.appendChild(message_container)
}
} else {
alert('The message was empty!')
}
scrollToBottom();
};
document.querySelector('#dm-message-input').focus();
// document.querySelector('#chat-message-input').click = function(e) {
// if (e.keyCode === 13) {
// console.log(e)
// document.querySelector('#chat-message-input').value += '\n';
// }
// };
document.querySelector('#dm-message-submit').onclick = function(e) {
e.preventDefault()
const messageInputDom = document.querySelector('#dm-message-input');
const message = messageInputDom.value;
if(message === "" || !message.match(/\S/g)){
return false
}
console.log({
'message': message,
'username': userName,
'room': DmId
})
chatSocket.send(JSON.stringify({
'message': message,
'username': userName,
'dm': DmId
}));
messageInputDom.value = '';
return false
};
/**
* A function for finding the messages element, and scroll to the bottom of it.
*/
function scrollToBottom() {
let objDiv = document.getElementById("chat-messages");
objDiv.scrollTop = objDiv.scrollHeight;
}
// Add this below the function to trigger the scroll on load.
scrollToBottom();
})
0 likes