简体   繁体   中英

How to run WebSocket (django-channels) in production Pythonanywhere?

I created a simple chat app using WebSockets after following the official Django-channels tutorial. However, I can't get it to work in production. I have done a few google searching to find out a forum in Pythonanywhere saying that they don't support WebSocket, I contacted the team and they told me the same thing. I have done even more google searching and found things related to Daphne server, Nginx, and a few other things I never heard about before.

As I'm new to Django-channels I'm currently very confused! Is there something I can do to make my WebSocket website run normally in Pythonanywhere on production (for free of course) Or I have to delete all of the WebSocket code and replace it with repetitive Http called to check of new messages (With AJAX)?

And if there is no other solution but to move to repetitive Http calls, is there any other web hosting service that offers free play which includes free SSL certification, the domain name (such as mydomain.servicename.com) instead of random characters, and WebSocket support?

Thanks

the code i use

I don't know if it was relevant, also it's working perfect in development so i don't think there is an error in it

settings.py:

from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
from chat.routing import websocket_urlpatterns as chat_routing

application = ProtocolTypeRouter({
    "websocket": AuthMiddlewareStack(
        URLRouter(
            chat_routing,
        )
    )
})

main routing.py (in route folder)

from django.urls import path
from . import consumers

websocket_urlpatterns = [
    path('ws/chat/room/<int:room_id>/', consumers.RoomConsumer),
]

routing.py for chat app

import json
from channels.generic.websocket import AsyncWebsocketConsumer


class RoomConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        self.group_name = str(self.scope['url_route']['kwargs']['room_id'])
        await self.channel_layer.group_add(self.group_name, self.channel_name)
        await self.accept()

    async def disconnect(self, code):
        await self.channel_layer.group_discard(self.group_name, self.channel_layer)

    async def receive(self, text_data):
        message_json = json.loads(text_data)
        await self.channel_layer.group_send(self.group_name, {
            'type': 'send_message',
            'content': message_json['content'],
            'area': message_json['area'],
            'area_id': message_json['area_id'],
            'username': self.scope['user'].username,

        })

    async def send_message(self, event):
        await self.send(json.dumps(event))

consumers.py

<script>
        // -------------------
        // WEBSOCKET SETUP
        // -------------------
        var wsStart = 'ws://'
        var hostName = window.location.hostname + ':8000'
        if (window.location.protocol.includes('https')) {
            wsStart = 'wss://'
            hostName = window.location.hostname
        };
        let endpoint = wsStart + hostName + '/ws' + window.location.pathname
        console.log(endpoint)
        var socket = new WebSocket(endpoint);

        socket.onmessage = function (e) {
            // todo not show message if in a different room
            data = JSON.parse(e.data);
            console.log(data.area_id)
            console.log(data.area)
            var sender = 'other'
            var username = data.username
            if (data.username == "{{ user.username }}") {
                sender = 'self';
                username = 'You'
            }
            document.querySelector('.messages').innerHTML += `
            <div class="message ${sender}">
            <p>${username} &mdash; ${data.area}:</p>
            <p>${data.content}</p>
        </div>
            `
            document.querySelector('#notification_sound').play()
        }
        socket.onerror = function (e) {
            alert("SERVER ERROR 500, You won't be able to see messages unless you refresh,")
        }
        socket.onclose = function (e) {}

        document.addEventListener('DOMContentLoaded', function () {
            document.querySelector('#sendMessage').onclick = function (e) {
                e.preventDefault();
                // ------------AJAX: SEND AND MESSAGE---------------
                let xhr = new XMLHttpRequest();
                xhr.onreadystatechange = function (e) {
                    if (this.readyState == 4 && this.status == 200) {
                        document.querySelector('#id_content').value = '';
                    }
                }
                xhr.open("POST", "{% url 'chat:room' room.id %}", true);
                xhr.setRequestHeader('Content-type', "application/x-www-form-urlencoded");
                data = {
                    'csrfmiddlewaretoken': '{{ csrf_token }}',
                    'content': document.querySelector('#id_content').value,
                    'area': parseInt(document.querySelector('#id_area').value),
                }
                xhr.send(JSON.stringify(data));

                // ---------------WEBSOCKET: ECHO MESSAGE---------------
                let area = document.getElementById('id_area')
                socket.send(JSON.stringify({
                    'content': document.querySelector('#id_content').value,
                    'area': area.options[area.selectedIndex].text,
                    'area_id': document.querySelector('#id_area').value
                }));
            }
        });
    </script>

full js script

<script> // ------------------- // WEBSOCKET SETUP // ------------------- var wsStart = 'ws://' var hostName = window.location.hostname + ':8000' if (window.location.protocol.includes('https')) { wsStart = 'wss://' hostName = window.location.hostname }; let endpoint = wsStart + hostName + '/ws' + window.location.pathname console.log(endpoint) var socket = new WebSocket(endpoint); socket.onmessage = function (e) { // todo not show message if in a different room data = JSON.parse(e.data); console.log(data.area_id) console.log(data.area) var sender = 'other' var username = data.username if (data.username == "{{ user.username }}") { sender = 'self'; username = 'You' } document.querySelector('.messages').innerHTML += ` <div class="message ${sender}"> <p>${username} &mdash; ${data.area}:</p> <p>${data.content}</p> </div> ` document.querySelector('#notification_sound').play() } socket.onerror = function (e) { alert("SERVER ERROR 500, You won't be able to see messages unless you refresh,") } socket.onclose = function (e) {} document.addEventListener('DOMContentLoaded', function () { document.querySelector('#sendMessage').onclick = function (e) { e.preventDefault(); // ------------AJAX: SEND AND MESSAGE--------------- let xhr = new XMLHttpRequest(); xhr.onreadystatechange = function (e) { if (this.readyState == 4 && this.status == 200) { document.querySelector('#id_content').value = ''; } } xhr.open("POST", "{% url 'chat:room' room.id %}", true); xhr.setRequestHeader('Content-type', "application/x-www-form-urlencoded"); data = { 'csrfmiddlewaretoken': '{{ csrf_token }}', 'content': document.querySelector('#id_content').value, 'area': parseInt(document.querySelector('#id_area').value), } xhr.send(JSON.stringify(data)); // ---------------WEBSOCKET: ECHO MESSAGE--------------- let area = document.getElementById('id_area') socket.send(JSON.stringify({ 'content': document.querySelector('#id_content').value, 'area': area.options[area.selectedIndex].text, 'area_id': document.querySelector('#id_area').value })); } }); </script>

PythonAnywhere 不支持 Websockets,因此也不支持 django-channels。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM