1、Channels
Django
本身不支持WebSocket
,但可以通过集成Channels
框架来实现WebSocket
Channels
是针对Django
项目的一个增强框架,可以使Django
不仅支持HTTP协议,还能支持WebSocket
,MQTT
等多种协议,同时Channels
还整合了Django
的auth
以及session
系统方便进行用户管理及认证。
2、Channels实现websocket的方案
channels
运行于ASGI
协议上,所以需要ASGI
服务器运行django
,如daphne
。- 定义
websocket
路由 - 创建
webscoket consumer
,在这里实现创建、断开连接,发送、接收消息等。
3、步骤
3.1 依赖
channels
:3.0.5 , 要求你的redis
版本大于等于5.0daphne
:3.0.2,Daphne
是一个用于运行Django Channels
应用程序的异步Web服务器。channels-redis
:4.2.0django
:4.1.6python
:3.11
3.2 配置settings
-
ASGI
配置:指定ASGI
的路由地址,即asgi.py# ASGI 配置 ASGI_APPLICATION = ('xx.asgi.application')
-
INSTALLED_APPS
添加channels
。 -
django
启动时,在INSTALLED_APPS
检测到channels
,它就会要求使用ASGI
服务器运行。# channels 配置 INSTALLED_APPS = [ 'daphne', …… 'channels', …… ]
-
CHANNEL_LAYERS
配置:CHANNEL_LAYERS = { 'default': { 'BACKEND': 'channels_redis.core.RedisChannelLayer', 'CONFIG': { 'hosts': [('127.0.0.1', 6379)], }, }, }
3.3 修改asgi.py
配置 ASGI
应用程序的路由和协议处理器,分别配置http协议的路由和websocekt协议的路由。
import os
from django.core.asgi import get_asgi_application
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
from xxx.websocket.routing import websocket_urlpatterns
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'system.settings')
application = ProtocolTypeRouter(
{
'http': get_asgi_application(),
'websocket': AuthMiddlewareStack(URLRouter(websocket_urlpatterns))
}
)
ProtocolTypeRouter
:一个用于根据协议类型路由请求的路由器。在这个示例中,它会根据请求的协议类型来选择相应的处理程序。get_asgi_application()
:get_asgi_application()
是Django
的函数,它返回一个ASGI
应用程序,用于处理HTTP
请求。通常情况下,这个处理程序就是你的Django
应用程序,它会处理传统的HTTP
请求。AuthMiddlewareStack(URLRouter(websocket_urlpatterns))
:这里指定了WebSocket
协议的处理程序。AuthMiddlewareStack
是一个中间件,用于处理WebSocket
连接的认证。- 当
WebSocket
连接建立时,AuthMiddlewareStack
会检查用户是否已经通过身份验证。如果用户已经通过身份验证,那么WebSocket
连接就会被允许建立;否则,连接会被拒绝。 `URLRouter
是一个路由器,用于根据WebSocket
请求的URL
路由到相应的处理程序。websocket_urlpatterns
是一个列表,包含了定义WebSocket
路由和处理程序的URL
模式。
3.4 创建websocket消费者
在app
下创建websocket
文件夹,在该文件夹下创建consumers.py
。
一个简单的消费者的例子:
import json
from channels.generic.websocket import AsyncWebsocketConsumer
class TestConsumer(AsyncWebsocketConsumer):
async def connect(self):
await self.accept()
async def disconnect(self, code):
pass
async def receive(self, text_data=None, bytes_data=None):
text_data_json = json.loads(text_data)
message = text_data_json["message"]
# 设置ensure_ascii以支持中文
await self.send(text_data=json.dumps({"message": message}, ensure_ascii=False))
async def send_message(self, event):
message = event['message']
await self.send(text_data=json.dumps(message))
这就是一个消费者的模板,首先要继承AsyncWebsocketConsumer
类,然后可以重写connect
、disconnect
、receive
方法来满足我们的需要。
connect
:当 WebSocket 连接建立时会调用该方法disconnect
:当 WebSocket 连接关闭时会调用该方法。 注意前端正常断开连接时会正确调用该方法;如果因为后端挂了而导致连接断开的话,不会调用该方法。-
receive
:连接建立后收到消息时会调用方法 -
send_message
有些不同,它是我自己写的一个方法,最终调用的是父类的send
方法来推送消息。
3.4 创建websocket路由
consumers.py
同级下创建routing.py
。
from django.urls import path
from .consumers import TestConsumer
websocket_urlpatterns = [
path('ws/test/', TestConsumer.as_asgi()),
]
可以把websocket
就看做django
的路由和视图
现在前端可以连接这个路由,建立websocket
连接了。
ws://127.0.0.1:8000/ws/test/
:注意websocket
是以ws
开头。
3.5 路由参数可选
路由参数可选为了复用消费者,没必要创建多个消费者。
这种情况下需要创建两个或者多个路由,来分别匹配不同数量的参数。
from django.urls import path
from function.socket import consumers
websocket_urlpatterns = [
path('ws/datasend/<str:id>/', consumers.TestConsumer.as_asgi()),
path('ws/datasend/<str:id>/<str:name>/', consumers.TestConsumer.as_asgi())
]
接下来就可以在TestConsumer
这个消费者里做判断了
async def connect(self):
self.id = self.scope['url_route']['kwargs'].get('id', None)
self.name = self.scope['url_route']['kwargs'].get('name', None)
if self.name:
# name传递时的逻辑
else:
# name不传递时的逻辑
await self.accept()
4 self.send
方法详解
self.send
方法用于将数据发送到与当前 WebSocket 连接关联的客户端。该方法是异步的,需要使用 await
关键字调用,以确保不会阻塞事件循环。
await self.send(text_data=None, bytes_data=None, close=False)
text_data
:要发送的文本数据。必须是字符串类型。如果设置了此参数,则不能设置bytes_data
。bytes_data
:要发送的二进制数据。必须是字节类型。如果设置了此参数,则不能设置text_data
。close
:如果为True
,表示在发送完消息后关闭 WebSocket 连接。
5、channels-redis
channels-redis
是 Django Channels
框架的一个插件,用于在基于 Django Channels
的应用程序中实现分布式消息传递和状态保持。它提供了一个基于 Redis
的通道层,用于在多个异步进程之间传递消息和维护连接状态。
在使用 Django Channels
构建实时应用程序时,通常需要处理多个进程或服务器之间的通信和状态同步。channels-redis
正是为了解决这个问题而设计的。它通过 Redis
数据库作为后端存储来实现通信和状态同步,Redis
提供了高性能和可靠的分布式数据存储,适合用于构建实时应用程序。
channels-redis
的主要功能包括:
- 分布式消息传递:允许在多个异步进程或服务器之间传递消息,例如
WebSocket
消息、后台任务消息等。 - 状态保持:维护连接状态和客户端会话信息,使得在分布式环境中实现实时应用程序变得更加容易。
- 后台任务队列:允许在多个工作者之间分配和执行后台任务,例如发送电子邮件、处理图像等。
通过使用 channels-redis
,开发者可以轻松地构建具有高可扩展性和高可靠性的实时应用程序,而无需担心多进程之间的通信和状态同步问题。
评论列表,共 0 条评论
暂无评论