解决websocket使用uWSGI+nginx路由丢失

当你的django项目中使用channels增加了websocket功能的时候,在使用runserver命令启动时,既可以访问http请求,又可以访问websocket请求。但是当你使用uWSGI+nginx的来启动项目的时候,你会发现http请求可用,但是websocket请求永远是404的错误。这是为什么呢?
? 因为在我们的标准生产环境部署中,使用的事WSGI协议来启动的我们的项目,也就是使用的wsgi.py这个文件来对接的uWSGI服务器。但是我们channels使用的ASGI协议,在我们使用uWSGI来启动项目的时候,关于ASGI的一些配置他就找不到了。这就导致了你所有的websocket请求都是404。在查阅了大量的资料和阅读了官方文档以后终于解决了这个问题。

这个问题的解决有两种方案:

  • 启用uWSGI来处理所有的http请求,另外开启一个daphne服务来处理websocket请求。这样的好处是按照请求类型分流,两种请求方式互不干扰。
  • 另外一种则是启用daphne服务来处理http和websocket这两种请求。在daphne服务内部他会根据请求类型的不同分开处理。让你既可以访问websocket又可以访问http。

安装Daphne

pip install daphne

在setting.py同级的目录下新建一个asgi.py文件

#asgi.py

"""
ASGI entrypoint. Configures Django and then runs the application
defined in the ASGI_APPLICATION setting.
"""

import os
import django
from channels.routing import get_default_application

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

使用Daphne来启动项目

daphne -b 0.0.0.0 -p 8001 myproject.asgi:application

 

什么是supervisor

  • Supervisor是用Python开发的一个client/server服务,是Linux/Unix系统下的一个进程管理工具,不支持Windows系统。
  • 作用:它可以很方便的监听、启动、停止、重启一个或多个进程。
  • 用Supervisor管理的进程,当一个进程意外被杀死,supervisort监听到进程死后,会自动将它重新拉起
  • 很方便的做到进程自动恢复的功能,不再需要自己写shell脚本来控制。
  • 说白了,它真正有用的功能是俩个将非daemon(守护进程)程序变成deamon方式运行对程序进行监控,当程序退出时,可以自动拉起程序。
  • 但是它无法控制本身就是daemon的服务。

 

安装supervisor

pip install supervisor或者yum install supervisor

使用supervisor

在/etc/supervisor/conf.d文件夹下面配置被管理的服务的配置,然后启动supervisor即可管理该服务。

下面使用supervisor来管理我们dephne服务

[fcgi-program:asgi]     #项目的名字,program后面的名字为被管理的项目的名字,启动和关闭操作时都是操作这个名字
# TCP socket used by Nginx backend upstream
socket=tcp://0.0.0.0:8000    #是不是很熟悉?哈哈,这个就是和nginx服务通信时接收数据的端口

# Directory where your site‘s project files are located
directory=/my/app/path       #项目的路径

# Each process needs to have a separate socket file, so we use process_num
# Make sure to update "mysite.asgi" to match your project name
#项目的启动命令,你只需要修改mysite为你自己项目的名字即可
command=daphne -u /run/daphne/daphne%(process_num)d.sock --fd 0 --access-log - --proxy-headers mysite.asgi:application

# Number of processes to startup, roughly the number of CPUs you have
#启动的进程的数量
numprocs=4

# Give each process a unique name so they can be told apart
#每个进程的名字
process_name=asgi%(process_num)d

# Automatically start and recover processes
#自动启动自动恢复
autostart=true
autorestart=true

# Choose where you want your log to go
#daphne服务的日志文件
stdout_logfile=/your/log/asgi.log
#如果为true,则stderr的日志会被写入stdout日志文件中默认为false,非必须设置
redirect_stderr=true

supervisor配置

 

supervisore的管理命令

supervisord -c /etc/supervisord.conf  # 启动supervisor
[ tmp]# supervisorctl status                            # 查看supervisor管理的所有进程状态
[ supervisord.d]# supervisorctl restart test            # 启动test程序
[ supervisord.d]# supervisorctl stop all                # 停止所有程序
supervisorctl stop es       # 停止名称es程序(如果停止所有换成all)
[ tmp]# supervisorctl start es      # 启动项目名称es程序
[ tmp]# supervisorctl update        # 配置文件修改后使用该命令加载新的配置
[ tmp]# supervisorctl reload        # 重新启动配置中的所有程序

接下来就是配置nginx将请求转发发哦daphne服务器

upstream channels-backend {
    server localhost:8000;
}
...
server {
    ...
    location / {
        try_files $uri @proxy_to_app;
    }
    ...
    location @proxy_to_app {
        proxy_pass http://channels-backend;

        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;
    }
    ...
}

开启你的nginx服务和dephne服务即可

systemctl restart nginx   #重启nginx
supervisorctl reload            #重新加载supervisor
supervisorctl update            #更新supervisor的配置
supervisorctl start asgi    #启动asgi服务,也就是我们的daphne服务

相关推荐