@shogoshinoda (Shinoda Shogo)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

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

No Answers yet.

Your answer might help someone💌