如何在 Pythonanywhere 生产环境中 运行 WebSocket (django-channels)?
How to run WebSocket (django-channels) in production Pythonanywhere?
在学习了官方 Django-channels 教程后,我使用 WebSockets 创建了一个简单的聊天应用程序。但是,我无法让它在生产中工作。我做了一些 google 搜索,在 Pythonanywhere 中找到一个论坛,说他们不支持 WebSocket,我联系了团队,他们告诉我同样的事情。
我做了更多 google 搜索,发现了与 Daphne 服务器、Nginx 和其他一些我以前从未听说过的东西相关的东西。
由于我是 Django 频道的新手,所以我现在很困惑!我可以做些什么来使我的 WebSocket 网站 运行 在 Pythonanywhere 中正常生产(当然是免费的)或者我必须删除所有 WebSocket 代码并将其替换为重复的 Http 调用以检查新消息(用 AJAX)?
如果没有其他解决方案,只能转向重复的 Http 调用,是否有任何其他网络托管服务提供免费播放,包括免费 SSL 认证、域名(例如 mydomain.servicename.com)随机字符和 WebSocket 支持?
谢谢
我使用的代码
我不知道它是否相关,而且它在开发中也很完美,所以我认为它没有错误
settings.py:
INSTALLED_APPS = [
'channels',
...
'django_cleanup',
]
ASGI_APPLICATION = 'orgachat.routing.application'
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': {
"hosts": [('127.0.0.1', 6379)],
},
},
}
main routing.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,
)
)
})
routing.py 用于聊天应用
from django.urls import path
from . import consumers
websocket_urlpatterns = [
path('ws/chat/room/<int:room_id>/', consumers.RoomConsumer),
]
consumers.py
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))
完整的 js 脚本
<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} — ${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>
Websockets,因此 django-channels 在 PythonAnywhere 上不受支持。
在学习了官方 Django-channels 教程后,我使用 WebSockets 创建了一个简单的聊天应用程序。但是,我无法让它在生产中工作。我做了一些 google 搜索,在 Pythonanywhere 中找到一个论坛,说他们不支持 WebSocket,我联系了团队,他们告诉我同样的事情。 我做了更多 google 搜索,发现了与 Daphne 服务器、Nginx 和其他一些我以前从未听说过的东西相关的东西。
由于我是 Django 频道的新手,所以我现在很困惑!我可以做些什么来使我的 WebSocket 网站 运行 在 Pythonanywhere 中正常生产(当然是免费的)或者我必须删除所有 WebSocket 代码并将其替换为重复的 Http 调用以检查新消息(用 AJAX)?
如果没有其他解决方案,只能转向重复的 Http 调用,是否有任何其他网络托管服务提供免费播放,包括免费 SSL 认证、域名(例如 mydomain.servicename.com)随机字符和 WebSocket 支持?
谢谢
我使用的代码
我不知道它是否相关,而且它在开发中也很完美,所以我认为它没有错误settings.py:
INSTALLED_APPS = [
'channels',
...
'django_cleanup',
]
ASGI_APPLICATION = 'orgachat.routing.application'
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': {
"hosts": [('127.0.0.1', 6379)],
},
},
}
main routing.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,
)
)
})
routing.py 用于聊天应用
from django.urls import path
from . import consumers
websocket_urlpatterns = [
path('ws/chat/room/<int:room_id>/', consumers.RoomConsumer),
]
consumers.py
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))
完整的 js 脚本
<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} — ${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>
Websockets,因此 django-channels 在 PythonAnywhere 上不受支持。