Hi, I am using a Django Backend with React frontend… I want to use websockets to connect both ends. I have a docker service to run daphene and nginx to route all “ws/*” to daphene server. Here is the daphene service that i defined in docker:
websocket:
build: ./backend
command: daphne -b 0.0.0.0 -p 8001 core.asgi:application
volumes:
- ./backend:/crafter
- static_volume:/crafter/staticfiles/backend
environment:
- DJANGO_SETTINGS_MODULE=core.settings
ports:
- "8001:8001"
networks:
- crafter_network
depends_on:
- db
Here is my nginx
location /ws/ {
proxy_pass http://websocket:8001/;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_read_timeout 86400;
}
This is my consumer:
class TimelineConsumer(AsyncWebsocketConsumer):
"""
Handles realtime updates and deletions for timeline items
"""
async def connect(self):
# Set the group name for this connection
self.group_name = "timeline"
# Add this consumer to the group
await self.channel_layer.group_add(
self.group_name,
self.channel_name
)
# Accept the WebSocket connection
await self.accept()
async def disconnect(self, close_code):
# Remove this consumer from the group upon disconnection
await self.channel_layer.group_discard(
self.group_name,
self.channel_name
)
This is how I am connecting to my websocket
useEffect(() => {
const ws = new WebSocket("ws://localhost/ws/timeline/");
ws.onopen = () => {
console.log('WebSocket connection established.');
};
ws.onmessage = (event) => {
console.log('WebSocket message received:', event.data);
};
ws.onclose = () => {
console.log('WebSocket connection closed.');
};
return () => {
ws.close();
};
}, []);
I am getting this error in browser console:
WebSocket connection to 'ws://localhost/ws/timeline/' failed: WebSocket connection closed.
What does your docker logs for that container show? What do the nginx logs show?
THis is the log from nginx:
192.168.32.1 - - [12/Nov/2023:20:35:02 +0000] "GET /ws/timeline/ HTTP/1.1" 500 5 "-" "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1" "-"
This is the log from websocket container:
websocket_1 | 192.168.32.7:56652 - - [12/Nov/2023:21:37:16] "WSCONNECTING /timeline/" - -
backend_1 | GET /api/set_csrf/ HTTP/1.1 200 28
websocket_1 | 192.168.32.7:56668 - - [12/Nov/2023:21:37:16] "WSCONNECTING /timeline/" - -
websocket_1 | 2023-11-12 21:37:17,177 ERROR Exception inside application: No route found for path 'timeline/'.
websocket_1 | Traceback (most recent call last):
websocket_1 | File "/usr/local/lib/python3.11/site-packages/channels/routing.py", line 62, in __call__
websocket_1 | return await application(scope, receive, send)
websocket_1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
websocket_1 | File "/usr/local/lib/python3.11/site-packages/channels/routing.py", line 134, in __call__
websocket_1 | raise ValueError("No route found for path %r." % path)
websocket_1 | ValueError: No route found for path 'timeline/'.
websocket_1 | 2023-11-12 21:37:17,178 ERROR Exception inside application: No route found for path 'timeline/'.
websocket_1 | Traceback (most recent call last):
websocket_1 | File "/usr/local/lib/python3.11/site-packages/channels/routing.py", line 62, in __call__
websocket_1 | return await application(scope, receive, send)
websocket_1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
websocket_1 | File "/usr/local/lib/python3.11/site-packages/channels/routing.py", line 134, in __call__
websocket_1 | raise ValueError("No route found for path %r." % path)
websocket_1 | ValueError: No route found for path 'timeline/'.
websocket_1 | 192.168.32.7:56652 - - [12/Nov/2023:21:37:17] "WSDISCONNECT /timeline/" - -
websocket_1 | 192.168.32.7:56668 - - [12/Nov/2023:21:37:17] "WSDISCONNECT /timeline/" - -
Hi thanks for the quick reply, here’s what you requested for:
This is the logs from nginx container:
192.168.32.1 - - [12/Nov/2023:20:35:02 +0000] "GET /ws/timeline/ HTTP/1.1" 500 5 "-" "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1" "-"
This is the logs from websocket container:
websocket_1 | 192.168.32.7:56652 - - [12/Nov/2023:21:37:16] "WSCONNECTING /timeline/" - -
backend_1 | GET /api/set_csrf/ HTTP/1.1 200 28
websocket_1 | 192.168.32.7:56668 - - [12/Nov/2023:21:37:16] "WSCONNECTING /timeline/" - -
websocket_1 | 2023-11-12 21:37:17,177 ERROR Exception inside application: No route found for path 'timeline/'.
websocket_1 | Traceback (most recent call last):
websocket_1 | File "/usr/local/lib/python3.11/site-packages/channels/routing.py", line 62, in __call__
websocket_1 | return await application(scope, receive, send)
websocket_1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
websocket_1 | File "/usr/local/lib/python3.11/site-packages/channels/routing.py", line 134, in __call__
websocket_1 | raise ValueError("No route found for path %r." % path)
websocket_1 | ValueError: No route found for path 'timeline/'.
websocket_1 | 2023-11-12 21:37:17,178 ERROR Exception inside application: No route found for path 'timeline/'.
websocket_1 | Traceback (most recent call last):
websocket_1 | File "/usr/local/lib/python3.11/site-packages/channels/routing.py", line 62, in __call__
websocket_1 | return await application(scope, receive, send)
websocket_1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
websocket_1 | File "/usr/local/lib/python3.11/site-packages/channels/routing.py", line 134, in __call__
websocket_1 | raise ValueError("No route found for path %r." % path)
websocket_1 | ValueError: No route found for path 'timeline/'.
websocket_1 | 192.168.32.7:56652 - - [12/Nov/2023:21:37:17] "WSDISCONNECT /timeline/" - -
websocket_1 | 192.168.32.7:56668 - - [12/Nov/2023:21:37:17] "WSDISCONNECT /timeline/" - -
In case you ar einterested how I am dealing with the routings for websockets in django, here they are:
routing.py
# Set django settings module environment variable
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'core.settings')
django_asgi_app = get_asgi_application()
from timeline.consumers import TimelineConsumer
from api.consumers import SessionConsumer
ws_urlpatterns = [
path("ws/timeline/", TimelineConsumer.as_asgi()),
path('ws/sessionstatus/<str:user_hash>/', SessionConsumer.as_asgi()),
]
application = ProtocolTypeRouter({
'http': django_asgi_app,
"websocket": URLRouter(ws_urlpatterns),
})
settings.py
# Websockets channels
ASGI_APPLICATION = "core.routing.application"
CHANNEL_LAYERS = {
"default": {
"BACKEND": "channels.layers.InMemoryChannelLayer"
}
}
This is showing to you that nginx is only passing the timeline
portion of the request url through the proxy.
I believe you need to change this:
to this:
proxy_pass http://websocket:8001/ws/;
(Or, I believe you could also define it without the trailing slash as:)
proxy_pass http://websocket:8001;
Thank you so much for helping me out with this. Could you clear one thing to me? In the nginx logs why am I seeing “GET /ws/timeline/ HTTP/1.1” ? I thought its an WS route and it shouldnt show a REST Method…
It’s not a REST method. It’s a standard HTTP GET. (A websocket connection is a standard http request that gets upgraded to be a persistent TCP socket.)
ah I had the wrong idea of WS afterall, thanks, i thought of it as MQTT protocols
You could implement something like MQTT on top of a WebSocket, but MQTT assumes the existance of, or the ability to create, a socket.