Django使用Channels主动给客户端发送信息
最近做的Django项目中有一条需求是当用户写完邮件并选择抄送用户,用户发送邮件后,服务器主动会给在所有抄送用户发送一条提示。这里可以使用支持WebSoket协议的Channels。
思路简述:
- 用户登录时,浏览器会主动发送器WebScoket连接,服务器接到连接后,将用户加入以用户ID标识的组群中,并返回接受连接的信息;
- 发送邮件时,会遍历抄送用户的ID,根据他们的ID,一次向相应的组群发送消息
为了验证浏览器缺失收到了信息,先写一个简单的html页面用于显示收到的信息:
<!-- static/templates/notificationMsg.html -->
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"/><title>Chat Room</title>
</head>
<body><textarea id="notificationMsg-log" cols="100" rows="20"></textarea><br/>
</body>
<script>var userID = {{ userID }};var notificationMsgSocket = new WebSocket('ws://' + window.location.host +'/ws/notifications/' + userID + '/'); // 客户端发起WebSocket,并返回WebSocket对象命名为notificationMsgSocketnotificationMsgSocket.onmessage = function(e) { // 监听服务器发回的消息var data = JSON.parse(e.data); // 将消息中data的值转为JS对象var message = data['message']; // 获取其中message的值alert(message)document.querySelector('#notificationMsg-log').value += (message + '\n'); // 将message的值添加到notificationMsg-log中并换行};notificationMsgSocket.onclose = function(e) { // WebSocket的readyState变为CLOSED时调用console.error('Notification socket closed unexpectedly'); // 在控制台输出错误信息};
</script>
</html>
这个界面是根据channels文档给出的示例简化的,页面只有一个文本框,在收到服务器发送的消息时会显示出来。
消费者,事件
channels中用消费者(consumer)处理WebSocket中的事件(event),消费者可以理解为Django中的视图,事件可以看作HTTP中的request。
在ASGI中,事件以字典的形式传递给服务器,使用’type’键标记具体事件类型,不同的事件由同名的消费者处理,比如在这个项目中,每次发送’type’为’get_notification’的事件,则需要定义一个名为’get_notification’的消费者用于接受事件作出响应。
在视图中发送邮件通知:
13 from asgiref.sync import async_to_sync14 from channels.layers import get_channel_layer...31 class IssuedReportsView(View):...
110 def post(self, request):
...
160 ¦ send_message_users = set(copy_to_user+supervise_user) # 将抄送人与审阅人的id放到同一个集合中
161 ¦ channel_layer = get_channel_layer() # 实例化get_channel_layer()对象,用于向组群发送消息
162 ¦ for user in send_message_users: # 遍历需要发送消息的用户id
163 ¦ ¦ async_to_sync(channel_layer.group_send)( # ASGI是异步的,这里转为同步操作;通过通信层向组群发送消息
164 ¦ ¦ ¦ "notification_"+str(user), # 用户所在的组群
165 ¦ ¦ ¦ {
166 ¦ ¦ ¦ 'type':'get_notification', # 标记发送事件的type
167 ¦ ¦ ¦ 'message': 'you have got a new report', # 提示信息
168 ¦ ¦ ¦ }
169 ¦ ¦ )
定义channels的路由
channels需要一个根路由,官方建议放在配置目录下和settings.py同路径,用于分配不同的协议连接到不同的路由文件,这里仅处理WebSocket文件:
1 # myproject/routing.py2 from channels.routing import ProtocolTypeRouter, URLRouter3 from channels.auth import AuthMiddlewareStack4 import consumer.routing 5 6 7 application = ProtocolTypeRouter({ # 协议路由8 # (http->django views is added by default)9 'websocket': AuthMiddlewareStack( # 分发WebSocket连接,使用channels中的认证中间件,根据Django赋予request的session判断用户身份10 ¦ URLRouter(11 ¦ ¦ consumer.routing.websocket_urlpatterns # 根据consumer目录下的routing.py中的websocket_urlpatterns进一步分发websocket请求12 ¦ )13 ),14 })
根路由中指向的路由文件如下:
1 # myproject/consumer/routing.py2 3 from django.urls import re_path4 from channels.auth import AuthMiddlewareStack5 from consumer.Consumers import Consumers6 7 8 websocket_urlpatterns = [ 9 re_path(r'ws/notifications/(?P<userID>\w+)/$', Consumers), # 使用django的re_path方法,将匹配到的path交给不同的消费者处理 10 ]
注册
在settings.py中注册:
# 首先在INSTALLED_APPS中注册
INSTALLED_APPS = ['django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles','report','channels', # 注册channels
]
...
# 指定根路由文件,和下面的通信层一起放在文件尾部即可
ASGI_APPLICATION = 'starxteam.routing.application'
# 消费者中用到了通信层\channels.layer用于跨应用传递数据
# 但是需要使用第三方应用支持这个功能,官方推荐channels_redis
# 安装channels时默认安装了channels_redis
CHANNEL_LAYERS = {'default':{'BACKEND': 'channels_redis.core.RedisChannelLayer','CONFIG': {'hosts': [('127.0.0.1', 6379)], },},
}
使用POSTMAN测试一下:
前端收到了消息:
Django使用Channels主动给客户端发送信息相关推荐
- 服务器怎么向指定客户端发送信息,WebSocket 如何实现服务端向客户端发送消息?...
我们都知道, Websocket 是一个双向的通讯方式,一般情况下,我们都是根据 Client 的情况返回信息,但是在一个更加健壮的系统,我们可能需要主动的向客户端发送消息.我试图在中文网络去搜索,查 ...
- Android的SocketTCP客户端发送信息
通过Android Studio建立SocketTCP客户端发送字符串 上回书说到,STM32通过Socket建立TCP服务器之后可以通过TCP客户端来给它发出指令,但是电脑发指令就比较麻烦,所以花了 ...
- ssm配置socket_ssm框架中集成websocket实现服务端主动向客户端发送消息
找了很多配置文档及实例说明,也还是没能成功,最终在csdn博客中发现了基于stomp的消息推送的文章, 下面整理自csdn博客,https://blog.csdn.net/u013627689/art ...
- netty 服务端主动向客户端发信息
在使用netty时,有时候会和客户端保持长链接,这个时候服务端既可以接受客户端消息也可以主动发送消息给服务端.我们只需要在服务端保存客户端的ChannelHandlerContext对象,必要的时候通 ...
- Springboot中使用websocket发送信息给指定用户和群发
websocket是一种长连接协议,相较于传统的http短连接,websocket不仅可以由客户端向服务器发送消息,可以主动向客户端发起信息,经常用于及时聊天,游戏和服务器向客户端推送信息. 主要优点 ...
- SpringBoot2.x 整合websocket 消息推送,单独发送信息,群发信息
根据公司需求在SpringBoot项目中集成站内信,于是,我做了一个SpringBoot2.x 整合websocket 消息推送,给指定用户发送信息和群发信息即点点对方式和广播方式2种模式. 文章目录 ...
- C# SuperSocket 手把手教你入门 傻瓜教程---1(服务器单向接收客户端发送数据)
C# SuperSocket 手把手教你入门 傻瓜教程系列教程 C# SuperSocket 手把手教你入门 傻瓜教程---1(服务器单向接收客户端发送数据) C# SuperSocket 手把手教你 ...
- Nerry实现服务器端指定客户端发送消息。
目录 pom依赖 Server端 main方法初始化netty 服务端端主动给客户端发送消息 pom依赖 <dependency><groupId>io.netty</g ...
- http协议与https协议+UDP协议和TCP协议+WebSocket协议下服务端主动去发送信息+对称加密与非对称加密+get和post请求方式区别详解+浏览器内核以及jsj解析引擎
TCP和UDP协议是TCP/IP协议的核心. 在TCP/IP网络体系结构中,TCP(传输控制协议,Transport Control Protocol).UDP(用户数据报协议,User Data P ...
最新文章
- HSQLDB安装与使用
- iOS 实现加载转圈效果
- VMware Workstation 与 Hyper-V 不兼容。请先从系统中移除 Hyper-V 角色
- uni-app与Vue的区别
- 指定版本的python运行和指定python版本的pip
- wordpress 当前栏目名,当前栏目的分类名
- android studio背景模糊_[Android翻译]CameraX:过去、现在和未来的一瞥
- 【TensorFlow】TensorFlow函数精讲之tf.contrib.layers.flatten()
- MySQL当查询的时候有多个结果,但需要返回一条的情况用GROUP_CONCAT拼接
- 用SQL Server(T-SQL)获取连接字符串
- Java项目:医院病历信息管理系统(java+SSM+JSP+bootstrap+easyui+Mysql)
- JavaScript实现简单计算器
- nandflash驱动分析 针对K9GAG08U0D uboot1.1.6(上)
- json转xml报[java.lang.NoClassDefFoundError: nu/xom/Serializer]
- module_platform_driver()
- Netty快速学习1-基础知识回顾
- 基于 Servlet + jsp 的企业财务管理系统设计与实现
- 关于微信小程序通讯录人名分组的实现
- 线性表之线性表与数组的区别
- 快速拆分excel表格-python