1、Consumer的继承关系

- 推荐使用:
- AsyncWebsocketConsumer:适合于channels项目
- AsyncJsonWebsocketConsumer:适合于drf+channels项目
- api示例:(下面为伪代码,只是为了展示一下api的使用)
class MyAsyncConsumer(AsyncWebsocketConsumer) :
async def connect(self) :
await self.accept()
await self.accept(subprotocol="your protocol")
await self.close(code=403)
async def receive(self, text_data=None,bytes_data=None) :
await self.send(text_data="wuhha test")
await self.send (bytes_data="wuhha test")
await self.close()
async def disconnect(self, code) :
pass
import json
from channels.generic.websocket import AsyncWebsocketConsumer
class MessagesConsumer(AsyncWebsocketConsumer):
"""处理私信应用中的WebSocket请求"""
async def connect(self):
if self.scope['user'].is_anonymous:
await self.close()
else:
await self.channel_layer.group_add(self.scope['user'].username, self.channel_name)
await self.accept()
async def receive(self, text_data=None, bytes_data=None):
"""接收私信"""
await self.send(text_data=json.dumps(text_data))
async def disconnect(self, code):
"""离开聊天组"""
await self.channel_layer.group_discard(self.scope['user'].username, self.channel_name)
- 说明:
- 继承了Consumer体系中的某个类后,就可以算作是频道层管理器实例。
- 所有基于SyncConsumer或AsyncConsumer的consumer(即:频道层管理器实例)都提供了两个属性:self.channel_layer和self.channel_name属性,分别为指向channel layer的指针和consumer的channel layer的名字
- 对于channel layer的方法(包括send()、group_send(),group_add()等)都属于异步方法,这意味着在调用的时候都需要使用await;同时这也意味着如果想要从同步代码调用频道层管理器实例中的异步方法,就需要使用装饰器
asgiref.sync.async_to_sync
。类似的提供了同步与异步相互转换功能的api有:
2、ASGI的接口规范和WSGI接口规范中,作用类似的api【左为WSGI,右为ASGI】
self.request
【在视图中】 VS self.scope
【在消费者中】- 获取协议类型:
无
【WSGI只支持Http协议,也不需要这个api】 VS self.scope["type"]
- 获取url中关键字参数:
self.kwargs[【参数名】]
VS self.scope['url _route']['kwargs'] [【参数名】]
3、channels如何通过ORM保存和获取数据?
- 问题分析:ORM是同步操作;channels所有操作都是异步的
- 问题解决:channels提供了api——database_sync_to_async来实现将同步的ORM操作转为异步。
- 实现示例:
user = User.objects.get(username=username)
from channels.db import database_sync_to_async
user = await database_sync_to_async(User.objects.get(username=username))
@database_sync_to_async
def get_username(username):
return User.objects.get(username=username)
4、channels如何兼容Django的认证系统?
- 背景:
- Django的认证系统是通过一系列中间件来实现的。有:
- CookieMiddleWare
- SessionMiddleWare
- AuthMiddleWare
- 还要受到配置文件中配置的ALLONED_HOSTS项的约束。
- channels自然也考虑到了这种问题,它提供了channels.auth.AuthMiddlewarestack和channels.security.websocket.AllowedHostsOriginValidator(读取配置的ALLONED_HOSTS项的值)这两个类,只要我们在配置其他协议的路由时将路由列表放到栈里,栈再包在校验器里,就可以通过认证了
- 说明:
- AuthMiddlewareStack用于webSocket认证,集成了CookieMiddleware,SessionMiddleware,AuthMiddleware,兼容Django认证系统。阅读源码不难看出,该类是通过函数闭包实现的:
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zmRPLPfk-1673342720036)(https://wiki.incv.net/upload/202204/07/qBVtsHcYkS/image.png)]{{{width=“auto” height=“auto”}}}
- OriginValidator或AllowedHostsOriginValidator可以防止通过WebSocket进行CSRF攻击
- 使用AllowedHostsOriginValidator,允许访问的源站点与settings.py文件中的ALLOWED_HOSTS相同
- OriginValidator需要于动添加允许访问的源站,如:
- 示例:
5、Django项目中引入channels后,各关键文件和配置的含义:
- asgi.py :介于网络协议服务和Python应用之间的标准接口,能够处理多种通用协议类型,包括HTTP、HTTP2和WebSocket
- channel_layers :在settings.py中配置,类似于一个通道,发送者(producer)在一端发送消息,消费者(consumer)在另外—端监听
- 不管是Http协议还是WebSocket协议的数据,都得经过这个频道层。如果是Websocket协议的频道,可以把数据缓存到redis里【借助redis实现队列的效果】
- routings.py:相当于Django中的urls.py
- consumers.py :相当于Django中的views.py
相关文章
- 【Django Channels】概述篇
- 【Django Channels】快速上手篇
- 【Django Channels】WebSocket协议实战篇
- 【Django Channels】附录篇