由于公司需要开发一个监控系统,前后端方案使用 Angular+Django进行开发,协议:Websocket
由于开发时Django + Weboscket配置时找到的文档多数较老,或者大多数复制粘贴,很多代码前后不对应,所以开贴记录一下。ps:第一次发帖,结构有不完善或者有问题的可以随时指出,看到就会回复了,问题会持续更新
1.Python + Django Websocket配置
Django项目安装及新建就不演示了(项目名称:my-project),文档比较多而且简单。正文开始配置Django Websocket
项目中使用到的库及版本号:
后端:
- Django==3.2.3 # 2.1.14升级上来的,最后没影响
- Channels==3.0.3
- channels-redis==3.2.0
服务器端:
- redis:6.2.1
1.安装依赖
- 安装Channels
pip install channels==3.0.3 pip install channels-redis==3.2.0
- 服务器docker安装配置Redis,并启动容器,映射端口:6379
docker pull redis:6.2.1 docker run -itd --name my-redis -p 6379:6379 redis
或者使用Rancher及K8s配置(推荐)
2.Django配置
- 配置 settings.py
- 注册channels
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'channels', # 注册channels ]
- 配置channels layer
ASGI_APPLICATION = 'my-project.routing.application' CHANNEL_LAYERS = { 'default': { 'BACKEND': 'channels_redis.core.RedisChannelLayer', 'CONFIG': { "hosts": [(REDIS_URL, REDIS_PORT)], # REDIS_URL:开发环境:服务器<ip>,K8s部署时,根据redis的<service_name>; REDIS_PORT : 6379 }, }, }
- 注册channels
- 配置路由
- 在my-project项目文件夹下面新建routing.py,(与上步中layer配置时的ASGI路径保持一致)
from channels.auth import AuthMiddlewareStack from channels.routing import ProtocolTypeRouter, URLRouter import consumer.routing # 下一步新建的消费者app application = ProtocolTypeRouter({ 'websocket': AuthMiddlewareStack( URLRouter( consumer.routing.websocket_urlpatterns ) ), })
- 在my-project项目文件夹下面新建routing.py,(与上步中layer配置时的ASGI路径保持一致)
3.Django消费者
- 创建consumer app
python manage.py startapp consumer
- 在consumer文件目录下新建routing.py
from django.conf.urls import url from consumer import consumer # 下一步新建的业务处理模块 websocket_urlpatterns = [ url(r'^ws/monitoring/(?P<group_name>[^/]+)', consumer.MyConsumer.as_asgi()) ]
- 在consumer文件目录下新建consumer.py 作为消费者业务处理模块
class MyConsumer(AsyncWebsocketConsumer): async def connect(self): self.group_name = self.scope['url_route']['kwargs']['group_name'] # group_name 与routing.py中配置的参数保持一致 # 收到连接时候处理, await self.channel_layer.group_add( self.group_name, self.channel_name ) await self.accept() async def disconnect(self, close_code): # 关闭channel时候处理 await self.channel_layer.group_discard( self.group_name, self.channel_name ) # 收到消息 公司项目是单向推送的,所以没有测试接收消息的片段,有需要的话自己测试下吧,欢迎反馈 async def receive(self, text_data): text_data_json = json.loads(text_data) message = text_data_json['message'] print("收到消息--》", message) # 发送消息到组 await self.channel_layer.group_send( self.chat_group_name, { 'type': 'client.message', 'message': message } ) # 处理客户端发来的消息 async def client_message(self, event): message = event['message'] # 发送消息到 WebSocket await self.send(text_data=json.dumps({ 'message': message }))
- 发送消息示例,新建send_channel_msg.py,可以在其他模块进行调用
from channels.layers import get_channel_layer from asgiref.sync import async_to_sync channel_layer = get_channel_layer() def send_channel_msg(group_name, msg): async_to_sync(channel_layer.group_send)(group_name,{"type": "client.message", "message": msg})
4.K8s部署
- 能力有限,只会通过Rancher进行部署
- 将所有文件 打包成Docker镜像,推荐Dockerfile
- Rancher ->Workloads->Deploy,部署后端服务代码,正确填写镜像名称及版本号(redis:6.2.1,及自己的镜像名称),添加端口映射
- Rancher-> Load Balancing->add ingress,填写path及workload,填写后端服务的端口号