在Debug了几天后 无奈放弃了(有大佬知道原因还请解惑) 今天重点:使用Channels替换掉dwebsocket来实现ws功能,并用Daphne + Nginx部署我有个业务逻辑是前端用户点击某个文件夹的下载按钮,会同时触发两个函数,
·
第一个函数是服务端接收到该文件夹路径并开始将其压缩成zip然后返回该zip包实现用户下载功能,
第二个函数是后端开始压缩的时候前端要去连接一个ws服务,连接成功后后端实时将压缩进度通过ws发送到前端展示
·
问题出在这两个函数竟然不是同时进行的,我本以为是多进程问题,添加了log功能后发现这两个函数同时触发的,只是在某个函数开始进行复杂 *** 作的时候另一个函数会等待其完成才会往下执行,它俩互相阻塞!
·
展示在前端的效果就是用户点击下载,出现了进度条是0%,等了十来秒服务端压缩好浏览器开始下载这个zip包了,这时进度条直接变100%
不同于dwebsocket ,Channels使用的asgi,它功能更强大,但配置相对dwebsocket来说稍复杂些,总共需要新增三个文件 (asgi.py, routing.py, consumers.py)流程如下: 1. 新增asgi.py先安装所需库
pip install channels
pip install channels-redis
该文件在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/(?P4. 修改views.pyw+)/$', consumers.ChatConsumer.as_asgi()), ]
该文件就是上边提到的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
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)