#python #django #docker #nginx #websocket
Вопрос:
Websocket с django, docker-compose, nginx, дафной.
Обычные http — соединения работают нормально, но из соединений websocket не поступает никаких выходных данных. Веб-сайт, похоже, не активен.
Подключение через javascript приводит к ошибке:
new WebSocket('ws://127.0.0.1:8000/ws/pollData');
// WebSocket connection to 'ws://127.0.0.1:8000/ws/pollData' failed:
или при подключении к ws://localhost/ws/Данные опроса:
new WebSocket('ws://localhost/ws/pollData');
// Unchecked runtime.lastError: Could not establish connection. Receiving end does not exist.
докер-compose.yaml
version: '3'
services:
volume_configurer:
image: busybox
volumes:
- shared:/shared:z
- static:/static:z
command: ["/bin/sh", "-c", "
mkdir -p /static;
chmod -R 777 /static;
mkdir -p /shared/sync;
chmod -R 777 /shared/sync;
echo STARTED > /shared/sync/volumesetter amp;amp; chmod a r /shared/sync/volumesetter"]
db:
container_name: postgresdb
image: postgres:latest
restart: always
env_file:
- project.env
ports:
- 5432:5432
volumes:
- postgres-data1:/var/lib/postgresql/data1:z
web:
build:
context: ./
dockerfile: ./mdb/Dockerfile
container_name: django
command: >
daphne mdb.asgi:application -b 0.0.0.0 -p 8000
env_file:
- project.env
expose:
- 8000
depends_on:
- db
volumes:
- ./mdb:/home/app/web/:z
- static:/home/app/web/static/:z
- shared:/uploads/:z
nginx:
container_name: nginx
image: nginx
restart: always
ports:
- 80:80
volumes:
- ./nginx:/etc/nginx/conf.d:z
- static:/home/app/web/static/:z
depends_on:
- web
- db
volumes:
postgres-data1:
static:
shared:
nginx.conf:
upstream mdb {
server django:8000;
}
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;
server_name localhost;
client_max_body_size 2000M;
location /static/ {
alias /home/app/web/static/;
}
location /ws/ {
proxy_pass http://mdb;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
}
location / {
try_files $uri @proxy_to_app;
}
location @proxy_to_app {
proxy_pass http://mdb;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
}
}
consumer.py
from channels.generic.websocket import WebsocketConsumer
import json
class DashConsumer(WebsocketConsumer):
def connect(self):
print('==================2')
self.accept()
def disconnect(self, close_code):
print('==================1')
pass
def receive(self, text_data):
print('==================0')
text_data_json = json.loads(text_data)
message = text_data_json['message']
self.send(text_data = json.dumps({
'message': message
})
)
From a python view, connecting to a websocket does not produce any output when connecting to ws://localhost:8000/ws/pollData
. However, it also doesn’t crash. Whereas when connecting to something else, say, ws://localhost/ws/pollData
, it crashes with ConnectionRefusedError: [Errno 111] Connection refused
. However, there’s no output from django when using ws.connect(), i.e., print('==================<->')
in consumer.py is not firing.
views.py
ws = websocket.WebSocket()
# does not print
print(ws.connect('ws://localhost:8000/ws/pollData'))
# also does not print
print(ws.send('{"message": "test from django"}'))
# prints "still here"
print('still here')
# this crashes
print(ws.connect('ws://localhost:8000/ws/pollData'))
# does not print
print('still here')
asgi.py
import os
from django.conf.urls import url
from django.core.asgi import get_asgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mdb.settings")
django_asgi_app = get_asgi_application()
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from chat.consumer import DashConsumer
application = ProtocolTypeRouter({
"http": django_asgi_app,
"websocket": AuthMiddlewareStack(
URLRouter([
url(r"^ws/pollData$", DashConsumer.as_asgi()),
])
),
})
settings.py
WSGI_APPLICATION = 'mdb.wsgi.application'
ASGI_APPLICATION = 'mdb.routing.application'
CHANNEL_LAYERS = {
"default": {
"BACKEND": "channels.layers.InMemoryChannelLayer"
},
}
Помощь очень ценится!
Редактировать:
Похоже, что javascript подключается при использовании адреса ws://localhost/ws/pollData
или ws://0.0.0.0/ws/pollData
, как в любом случае, происходит событие подключения, и на панели «Сеть» отображается открытое подключение к websocket. Однако в python оба эти адреса вызывают ConnectionRefusedError: [Errno 111] Connection refused
, т. е.:
ws = websocket.WebSocket()
# appears to connect but does not send anything to javascript
ws.connect('ws://localhost:8000/ws/pollData')
ws.send('{"message": "test from django"}')
# crashes
ws.connect('ws://localhost/ws/pollData')
# also crashes
ws.connect('ws://0.0.0.0/ws/pollData')
Ответ №1:
Изменение DashConsumer
на AsyncJsonWebsocketConsumer
наряду с замечанием того, что веб-сайт на самом деле был открыт в javascript по другому адресу (т. е. ws://localhost/ws/pollData
или ws://0.0.0.0/ws/pollData
), было решением.
class DashConsumer(AsyncJsonWebsocketConsumer):
print('==================0')
async def connect(self):
print('==================1')
self.groupname = 'dashboard'
await self.channel_layer.group_add(
self.groupname,
self.channel_name,
)
await self.accept()
async def disconnect(self, close_code):
print('==================2')
await self.channel_layer.group_discard(
self.groupname,
self.channel_name
)
async def receive(self, text_data):
print('==================3')
# ~ #datapoint = json.loads(text_data)
# ~ #val = datapoint['value']
val = text_data
await self.channel_layer.group_send(
self.groupname,
{
'type': 'deprocessing', #function name to run
'value': val #value to send function
}
)
print ('>>>>', text_data)
async def deprocessing(self, event):
print('==================4')
valOther = event['value']
valOther = f'IP VALUE: {valOther}'
# send for frontend
await self.send(text_data = json.dumps({'value2': valOther}))
views.py
ws = websocket.WebSocket()
ws.connect('ws://localhost:8000/ws/pollData')
ws.send('{"message": "test from django"}')