【问题标题】:Websocket with Django channels doesn't work, connection failed带有 Django 通道的 Websocket 不起作用,连接失败
【发布时间】:2019-01-27 01:24:07
【问题描述】:

大家好!

我用django-channels 创建了一个聊天室。每次我尝试在生产中通过网络套接字连接到我的聊天室时,它都会失败。 在本地它可以正常工作。

我在 digitalocean

上托管

点冻结:

channels==2.1.2
channels-redis==2.3.0
daphne==2.2.1
'''

我已经用

安装了redis-server
sudo apt-get install redis-server

这是我的设置。

INSTALLED_APPS = [
    # '''
   'channels',
    # '''
] 
CHANNEL_LAYERS = {
    'default': {
        'BACKEND': 'channels_redis.core.RedisChannelLayer',
        'CONFIG': {
            "hosts": [os.environ.get('REDIS_URL', 'redis://localhost:6379')],
        },
    },
}
ASGI_APPLICATION = "project_name.routing.application"

这是我的asgi.pywsgi.py

import os
import django
from channels.routing import get_default_application

from django.core.wsgi import get_wsgi_application

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project_name.settings")
django.setup()
application = get_default_application()

这是我的project_folder.rounting.py

application = ProtocolTypeRouter({
    'websocket':AllowedHostsOriginValidator(
        AuthMiddlewareStack(
            URLRouter([
                # my urls
            ])
        )
    )
})

我在 Firefox 中不断得到这个,在其他浏览器中也有类似的东西:

Firefox 无法与位于 wss://www.domain_name.com/url-to/1/XBv​​Zjr2pqdf6fhy/ 的服务器建立连接

但是它在本地工作。

更新

这是我的 js

var loc = window.location;
var wsStart = loc.protocol == "https:" ? "wss://" : "ws://"
var endpoint = wsStart + loc.host + loc.pathname
var socket = new ReconnectingWebSocket(endpoint);

socket.onmessage = function(e){
    // code
}

【问题讨论】:

  • 我已经尝试解决这个问题一个多月了/=您是否部署在 Ubuntu 上?
  • 嗨@Eu Chi ...我看到您正在使用wss(安全websocket)连接...您是否已保护它,并为正确的端口保护它?如果将所有内容都移到常规的旧 ws 会发生什么?
  • 是的,我正在使用 Ubuntu @Mint
  • 感谢@MichaelRoberts 的提问,我正在使用 SSL 连接,如果我在没有它的情况下尝试使用 ws,则会通过说 连接不安全 来拒绝连接
  • 不确定这是否有帮助:github.com/django/channels/issues/514

标签: django websocket redis django-channels daphne


【解决方案1】:

我终于解决了这个问题,让wsssl下使用wss://

对于那些面临同样问题的人。

请注意,我使用

  • gunicorn 仅作为 http 请求的 Web 服务器
  • daphne 作为ws 网络套接字的网络服务器
  • nginx 作为反向代理

asgi.py

import os
import django
from channels.routing import get_default_application

from django.core.wsgi import get_wsgi_application

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.settings")
django.setup()
application = get_default_application()

settings.py

ASGI_APPLICATION = "project.routing.application"

CHANNEL_LAYERS = {
    'default': {
        'BACKEND': 'channels_redis.core.RedisChannelLayer',
        'CONFIG': {
            "hosts": [(os.environ.get('REDIS_HOST', 'localhost'),6379)],
        },
    },
}

使用 django 设置 asgi 后,我使用 supervisorctl 保持 daphne 运行。在/etc/supervior/conf.d/中创建文件daphne_asgi.conf

daphne_asgi.conf

[program:asgi_daphne]

directory=/path/to/your/project

command=/executable/path/to/daphne --bind 0.0.0.0 --port 8010 project.asgi:application
# 0.0.0.0 ip of your website
# I choose the port 8010 for daphne

stdout_logfile=/path/to/log/daphne.log

autostart=true

autorestart=true

redirect_stderr=true

运行以下命令来更新启动守护进程

sudo supervisorctl reread
sudo supervisorctl update

这里是nginx的配置

map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}
upstream websocket {
    server 0.0.0.0:8010;
}

daphne 中使用的主机和端口...--bind 0.0.0.0 --port 8010

#redirection to a https
server {
    listen 80;
    server_name 0.0.0.0 example.com www.example.com;
    client_max_body_size 10M;
    return 301 https://www.example.com$request_uri;
}

server {
    listen 443 ssl default_server;
    server_name www.example.com;
    client_max_body_size 10M;

    # ssl configuration
    ...

    # normal http request, I use .sock
    location / {
        include proxy_params;
        proxy_pass http://unix:/path/to/project.sock;
    }

    # ws request /ws/
    location /ws/ {
        proxy_pass http://websocket;

         # this magic is needed for WebSocket
        proxy_http_version  1.1;
        proxy_set_header    Upgrade $http_upgrade;
        proxy_set_header    Connection $connection_upgrade;
        proxy_set_header    Host $http_host;
        proxy_set_header    X-Real-IP $remote_addr;
    }
}

请注意,我在我的 ws 网址中添加了 /ws/

application = ProtocolTypeRouter({

    'websocket':AllowedHostsOriginValidator(
        AuthMiddlewareStack(
            URLRouter(
                [
                    url(r'^ws/$', HelloConsumer),
                ]
            )
        )
    )
})

【讨论】:

  • 在supervisor里不用python manage.py runworker channels -v2
【解决方案2】:

最重要的是,使用 redis 5.0.9。否则会再次出现错误。

github.com/tporadowski/redis/releases获取它

【讨论】:

    猜你喜欢
    • 2023-02-25
    • 2016-12-08
    • 1970-01-01
    • 2022-10-13
    • 2023-03-09
    • 2023-01-19
    • 2021-07-03
    • 2019-05-31
    • 2020-07-17
    相关资源
    最近更新 更多