Django前后端分离项目Channels + Daphne + Nginx部署

Django前后端分离项目Channels + Daphne + Nginx部署,第1张

Django前后端分离项目Channels + Daphne + Nginx部署 前面我们使用了dwebsocket并使用gunicorn来将其部署在服务器上,但运行几天,我发现了个问题

我有个业务逻辑是前端用户点击某个文件夹的下载按钮,会同时触发两个函数
·
第一个函数是服务端接收到该文件夹路径并开始将其压缩成zip然后返回该zip包实现用户下载功能,
第二个函数是后端开始压缩的时候前端要去连接一个ws服务,连接成功后后端实时将压缩进度通过ws发送到前端展示
·
问题出在这两个函数竟然不是同时进行的,我本以为是多进程问题,添加了log功能后发现这两个函数同时触发的,只是在某个函数开始进行复杂 *** 作的时候另一个函数会等待其完成才会往下执行,它俩互相阻塞!
·
展示在前端的效果就是用户点击下载,出现了进度条是0%,等了十来秒服务端压缩好浏览器开始下载这个zip包了,这时进度条直接变100%

在Debug了几天后 无奈放弃了(有大佬知道原因还请解惑) 今天重点:使用Channels替换掉dwebsocket来实现ws功能,并用Daphne + Nginx部署

先安装所需库
pip install channels
pip install channels-redis

不同于dwebsocket ,Channels使用的asgi,它功能更强大,但配置相对dwebsocket来说稍复杂些,总共需要新增三个文件 (asgi.py, routing.py, consumers.py)流程如下: 1. 新增asgi.py

该文件在settings.py同级目录下,并且在Django3中才会在新建Django项目时默认生成,建议直接使用Django3,我的项目本来是用django2.2.5写的,我直接自己新建了个asgi.py文件,然后将虚拟环境的django升级成了3可以直接使用(Django2好像也能用,但需要一些 *** 作,想尝试的可以自行百度)

asgi.py内容:

import os

from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from django.core.asgi import get_asgi_application
# main_show是app的名字
import main_show.routing

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "file_share.settings")

application = ProtocolTypeRouter({
    # http请求使用这个
    "http": get_asgi_application(),

    # websocket请求使用这个
    "websocket": AuthMiddlewareStack(
        URLRouter(
            main_show.routing.websocket_urlpatterns
        )
    ),
})
2. 新增consumers.py

该文件在app文件夹里与views.py同级

import json
from channels.generic.websocket import AsyncWebsocketConsumer
import datetime


class ChatConsumer(AsyncWebsocketConsumer):
    # websocket建立连接时执行方法
    async def connect(self):
    # 从url里获取room名字,为每个room建立一个频道组
        self.room_name = self.scope['url_route']['kwargs']['room_name']
        self.room_group_name = 'chat_%s' % self.room_name

        # 将当前频道加入频道组
        await self.channel_layer.group_add(
            self.room_group_name,
            self.channel_name
        )

        # 接受所有websocket请求
        await self.accept()

    # websocket断开时执行方法
    async def disconnect(self, close_code):
        await self.channel_layer.group_discard(
            self.room_group_name,
            self.channel_name
        )

    # 从websocket接收到消息时执行函数
    async def receive(self, text_data=None, bytes_data=None):
        # text_data_json = json.loads(text_data)
        message = {'get_data': text_data}
        print(text_data)
        # 发送消息到频道组,频道组调用chat_message方法
        await self.channel_layer.group_send(
            self.room_group_name,
            {
                'type': 'chat_message',
                'message': message
            }
        )

    # 从频道组接收到消息后执行方法
    async def chat_message(self, event):
        message = event['message']
        await self.send(text_data=message)
3. 新增routing.py

该文件在app文件夹里与views.py同级

from django.urls import re_path

from . import consumers

websocket_urlpatterns = [
    re_path(r'ws/(?Pw+)/$', consumers.ChatConsumer.as_asgi()),
]

4. 修改views.py

该文件就是上边提到的views.py ^ - ^

from asgiref.sync import async_to_sync
from channels.layers import get_channel_layer
channel_layer = get_channel_layer()  # 实例化get_channel_layer()对象,用于向组群发送消息

def send_cha(channellayer, room_name, msg):
    async_to_sync(channellayer.group_send)(  # ASGI是异步的,这里转为同步 *** 作;通过通信层向组群发送消息
        "chat_%s" % room_name,  # 用户所在的组群
        {
            'type': 'chat_message',  # 标记发送事件的type
            'message': msg,  # 提示信息
        }
    )

# 然后在你需要服务端发送信息的地方调用这个 send_cha 函数就ok了
# send_cha(channel_layer, 'room_name', 'balabala')
5. 修改settings.py
# 设置ASGI应用
ASGI_APPLICATION = 'file_share.asgi.application'

# 设置通道层的通信后台 - 本地测试用
CHANNEL_LAYERS = {
    "default": {
        "BACKEND": "channels.layers.InMemoryChannelLayer" # 仅供调试使用 如果你懒得在本地机器上装redis的话
        # 服务器部署 使用redis
        # 'BACKEND': 'channels_redis.core.RedisChannelLayer',
        # 'CONFIG': {
        #     "hosts": [("127.0.0.1", 6379)],
        # }
    }
}
6. nginx配置:
server {
    listen 9532;
    server_name xx.xx.xx.xx;
    client_max_body_size 10240m;
    client_body_buffer_size 10000m;
    client_header_buffer_size 10000m;
    proxy_buffers 512 256M;
    proxy_buffer_size 256M;
    proxy_connect_timeout 6000;
    proxy_read_timeout 6000;
    proxy_send_timeout 6000;

location / {
    root   /juan/239file_share/web/; #3.dist文件的位置
    try_files $uri $uri/ /index.html;
    add_header 'Access-Control-Allow-Origin' *;
}


# channels websocket asgi 配置
location /ws_api {
            rewrite  ^.+ws_api/?(.*)$ / break;
            proxy_pass http://0.0.0.0:10020;
            proxy_http_version 1.1;
            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 Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
}

}

配置完成 启动:

启动django服务:
因为asgi相当于wsgi的扩展 并且我们在asgi.py文件中分别配置了http和websocket服务,所以直接用asgi启动就行了。

daphne 你的项目名.asgi:application -b 0.0.0.0 -p 8030
或者后台运行 nohup daphne 你的项目名.asgi:application -b 0.0.0.0 -p 8030 &

启动nginx

nginx

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5701568.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存