简体   繁体   English

Django 频道 - Websocket 连接失败

[英]Django Channels - Websocket connection failed

I am currently trying to setup my Django Channels chat app, and I have followed the Docs to the best of my understanding - Obviously when something doesn't go right, there's always a solution, but I am just having difficulties working out where I've gone wrong with getting this to work.我目前正在尝试设置我的 Django Channels 聊天应用程序,并且我已尽我所能遵循文档 - 显然,当某些事情不正确时,总会有一个解决方案,但我只是在确定我的位置时遇到了困难“让这个工作出错了。

So far I have installed Django Channels, correctly configured my channel_layer within settings.py, I have referenced the docs and other online tutorials with creating my consumer.py file, utils.py, views.py and chat.html template file.到目前为止,我已经安装了 Django Channels,在 settings.py 中正确配置了我的 channel_layer,我已经参考了文档和其他在线教程来创建我的 consumer.py 文件、utils.py、views.py 和 chat.html 模板文件。

I have also configured nginx, gunicorn, daphne and redis and I can confirm that all of these services are running.我还配置了 nginx、gunicorn、daphne 和 redis,我可以确认所有这些服务都在运行。 I have installed LetsEncrypt and have allowed the SSL port (443 for https connections).我已经安装了 LetsEncrypt 并允许使用 SSL 端口(https 连接为 443)。

I am currently accessing my Django website on a live production server like this: https://mydomain:8001 and the direct link to my chat is configured as https://mydomain:8001/messenger我目前正在像这样的实时生产服务器上访问我的 Django 网站:https://mydomain:8001 并且我聊天的直接链接配置为 https://mydomain:8001/messenger

(I have allowed port 8001 through my firewall) (我已经允许端口 8001 通过我的防火墙)

Here are the status messages I am getting from the chat page:以下是我从聊天页面收到的状态消息:

SUCCESS {response: "Successfully got the chat.", chatroom_id: 1}chatroom_id: 1response: "Successfully got the chat."__proto__: Object
(index):303 setupWebSocket: 1
(index):371 ChatSocket connecting..
WebSocket connection to 'wss://www.<mydomain>.com:8001/messenger/1/' failed: 
setupWebSocket @ (index):317
success @ (index):389
c @ jquery.min.js
fireWith @ jquery.min.js
l @ jquery.min.js
(anonymous) @ jquery.min.js
ChatSocket error Event {isTrusted: true, type: "error", target: WebSocket, currentTarget: WebSocket, eventPhase: 2, …}bubbles: falsecancelBubble: falsecancelable: falsecomposed: falsecurrentTarget: WebSocket {url: "wss://<mydomain>:8001/messenger/1/", readyState: 3, bufferedAmount: 0, onopen: null, onOpen: ƒ, …}defaultPrevented: falseeventPhase: 0isTrusted: truepath: []returnValue: truesrcElement: WebSocket {url: "wss://<mydomain>:8001/messenger/1/", readyState: 3, bufferedAmount: 0, onopen: null, onOpen: ƒ, …}target: WebSocket {url: "wss://<mydomain>:8001/messenger/1/", readyState: 3, bufferedAmount: 0, onopen: null, onOpen: ƒ, …}timeStamp: 43973.62500001327type: "error"__proto__: Event
(index):357 Chat socket closed.

Any help with troubleshooting this issue would be greatly appreciated.对解决此问题的任何帮助将不胜感激。 If you could advise on which files you should prefer to see, I will happily update my question with the contents of any requested files for my chat app.如果您可以建议您希望查看哪些文件,我将很乐意使用我的聊天应用程序请求的任何文件的内容来更新我的问题。 :-) :-)

Thank you!谢谢!

File Contents:文件内容:

nginx.conf配置文件

server {
    listen 80;
    server_name myapp mydomain.com www.mydomain.com;

    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        root /home/myapp;
    }

    location / {
        proxy_set_header Host $http_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-Proto $scheme;
        proxy_pass http://unix:/home/myapp/myapp.sock;
    }
    
    location /ws/ {
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_redirect off;
        proxy_pass https://127.0.0.1:8001;
    }
    
    location /wss/ {
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-for $proxy_add_x_forwarded_for;
                proxy_set_header Host $http_host;
                proxy_pass http://127.0.0.1:8001;
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
        }
}

routing.py路由.py

from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.security.websocket import AllowedHostsOriginValidator
from django.urls import path, re_path

from messenger.consumers import ChatConsumer


application = ProtocolTypeRouter({
    'websocket': AllowedHostsOriginValidator(
        AuthMiddlewareStack(
            URLRouter([
                
                    path('messenger/<room_id>/', ChatConsumer),
                    
            ])
        )
    ),
})

settings.py设置.py

CHANNEL_LAYERS = {
    'default': {
        'BACKEND': 'channels_redis.core.RedisChannelLayer',
        'CONFIG': {
            "hosts": [('127.0.0.1', 6379)],
        },
    },
}

Error I am receiving within Console: (index):317 WebSocket connection to 'wss://www.mydomain.com:8001/messenger/1/' failed:我在控制台中收到的错误:( (index):317 WebSocket connection to 'wss://www.mydomain.com:8001/messenger/1/' failed:

(Where it says mydomain.com, my actual domain is typed in there :) (它说 mydomain.com,我的实际域在那里输入:)

Latest Daphne Logs from journalctl来自journalctl最新达芙妮日志

Jun 21 14:22:56 myhostname.com python3[36088]: 2021-06-21 14:22:56,576 INFO     Starting server at ssl:8001:privateKey=/etc/letsencrypt/live/mydomain.com/privkey.pem:certKey=/etc/let>
Jun 21 14:22:56 myhostname.com python3[36088]: 2021-06-21 14:22:56,576 INFO     HTTP/2 support not enabled (install the http2 and tls Twisted extras)
Jun 21 14:22:56 myhostname.com python3[36088]: 2021-06-21 14:22:56,577 INFO     Configuring endpoint ssl:8001:privateKey=/etc/letsencrypt/live/mydomain.com/privkey.pem:certKey=/etc/l>
Jun 21 14:22:56 myhostname.com python3[36088]: 2021-06-21 14:22:56,584 INFO     Listening on TCP address 0.0.0.0:8001

Error in Daphne Log达芙妮日志中的错误

Jun 21 14:38:51 myhostname.com python3[36088]: Traceback (most myhostname.com python3[36088]:   File "/usr/local/lib/python3.6/site-packages/channels/routing.py", line 71, in __call__
Jun 21 14:38:51 myhostname.com python3[36088]:     return await application(scope, receive, send)
Jun 21 14:38:51 myhostname.com python3[36088]:   File "/usr/local/lib/python3.6/site-packages/channels/security/websocket.py", line 37, in __call__
Jun 21 14:38:51 myhostname.com python3[36088]:     return await self.application(scope, send, receive)
Jun 21 14:38:51 myhostname.com python3[36088]:   File "/usr/local/lib/python3.6/site-packages/channels/sessions.py", line 47, in __call__
Jun 21 14:38:51 myhostname.com python3[36088]:     return await self.inner(dict(scope, cookies=cookies), receive, send)
Jun 21 14:38:51 myhostname.com python3[36088]:   File "/usr/local/lib/python3.6/site-packages/channels/sessions.py", line 254, in __call__
Jun 21 14:38:51 myhostname.com python3[36088]:     return await self.inner(wrapper.scope, receive, wrapper.send)
Jun 21 14:38:51 myhostname.com python3[36088]:   File "/usr/local/lib/python3.6/site-packages/channels/auth.py", line 181, in __call__
Jun 21 14:38:51 myhostname.com python3[36088]:     return await super().__call__(scope, receive, send)
Jun 21 14:38:51 myhostname.com python3[36088]:   File "/usr/local/lib/python3.6/site-packages/channels/middleware.py", line 26, in __call__
Jun 21 14:38:51 myhostname.com python3[36088]:     return await self.inner(scope, receive, send)
Jun 21 14:38:51 myhostname.com python3[36088]:   File "/usr/local/lib/python3.6/site-packages/channels/routing.py", line 160, in __call__
Jun 21 14:38:51 myhostname.com python3[36088]:     send,
Jun 21 14:38:51 myhostname.com python3[36088]:   File "/usr/local/lib/python3.6/site-packages/asgiref/compatibility.py", line 33, in new_application
Jun 21 14:38:51 myhostname.com python3[36088]:     instance = application(scope)
Jun 21 14:38:51 myhostname.com python3[36088]:   File "/usr/local/lib/python3.6/site-packages/channels/generic/websocket.py", line 159, in __init__
Jun 21 14:38:51 myhostname.com python3[36088]:     super().__init__(*args, **kwargs)
Jun 21 14:38:51 myhostname.com python3[36088]: TypeError: object.__init__() takes no parameters

I think the issue is in the configuration.我认为问题出在配置上。 In the nginx, you have to specify the URL prefix, not the protocol, there is also no need to add both ws and wss .在 nginx 中,你必须指定 URL 前缀,而不是协议,也不需要同时添加wswss The nginx config must look similar to this nginx 配置必须与此类似

location /ws/ {
    proxy_set_header Host               $http_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;
    proxy_set_header X-Forwarded-Proto  $scheme;
    proxy_set_header X-Url-Scheme       $scheme;
    proxy_redirect off;

    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;

    proxy_pass http://127.0.0.1:8001;
}

So, to connect via a Websocket protocol, you have to access something under wss://www.<mydomain>.com:8001/ws/ .因此,要通过 Websocket 协议进行连接,您必须访问wss://www.<mydomain>.com:8001/ws/下的某些内容。 For this to work, your asgi routes have to also include the ws prefix.为此,您的 asgi 路由还必须包含ws前缀。 Also, you should use as_asgi() on the consumer.此外,您应该在消费者上使用as_asgi() ( https://channels.readthedocs.io/en/stable/topics/routing.html ) https://channels.readthedocs.io/en/stable/topics/routing.html

application = ProtocolTypeRouter({
    'websocket': AllowedHostsOriginValidator(
        AuthMiddlewareStack(
            URLRouter([
                    path('ws/messenger/<room_id>/', ChatConsumer.as_asgi()), 
            ])
        )
    ),
})

Now you should be able to connect to wss://www.<mydomain>.com:8001/ws/messenger/1/ (don't forget the ws !).现在您应该能够连接到wss://www.<mydomain>.com:8001/ws/messenger/1/ (不要忘记ws !)。

Finally got Django Channels working (Finally managed to get my Websocket connection working) - With many thanks to Alexandr for his assistance.终于让 Django Channels 工作了(终于让我的 Websocket 连接工作了) - 非常感谢 Alexandr 的帮助。

From the logs, I found the following error: ERROR: TypeError: object.__init__() takes exactly one argument (the instance to initialize)从日志中,我发现了以下错误: ERROR: TypeError: object.__init__() takes exactly one argument (the instance to initialize)

I forgot to append as_asgi() to the end of where I was calling my ChatConsumer.我忘记将as_asgi()附加到我调用 ChatConsumer 的末尾。 So I changed my routing path from:所以我改变了我的路由路径:

path('ws/messenger/<room_id>/', ChatConsumer),

TO

path('ws/messenger/<room_id>/', ChatConsumer.as_asgi()),

And my Websocket is now open and has successfully connected!我的 Websocket 现在已打开并已成功连接! Happy days!快乐的时光!

A big thank you again for all your help Alexandr!再次非常感谢您对亚历山大的所有帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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