Django实现websocket

Django实现websocket

  • WebSocket功能
  • 使用介绍
    • 安装
    • 配置
    • WebSocket接口--消息接收者的实现
    • scope
    • 通道层 channel layer
    • 部署
    • Web客户端连接
    • Mac客户端

WebSocket功能

WebSocket长连接一般用于实现实时功能,例如web端的消息通知、会话等场景。

使用 WebSocket 向 Django 项目添加实时功能,一般有两个选择:

  1. 使用 Django Channels,这是一个向 Django 添加 WebSocket 等功能的项目。 Django 完全支持这种方法。 但是,它需要切换到新的部署架构;

  2. 在 Django 项目旁边部署一个单独的 WebSocket 服务。

方法2的实现一般可以借助 django-sesame 去管理会话的鉴权,本文不做过多阐述,可以点击参考链接,下面组要介绍方法1中Channels在Django中的使用。

关于Channels:

  • 源码地址 https://github.com/django/channels
  • 文档介绍 https://channels.readthedocs.io/en/latest/

使用介绍

安装

pip install -U 'channels[daphne]'

需要使用daphne,是为了后续部署用于启动ASGI1服务。当然,若是你有其他的部署方式你可以仅安装channels。

配置

安装完后,需要在INSTALLED_APPS配置中添加:

INSTALLED_APPS = ("daphne","django.contrib.auth","django.contrib.contenttypes","django.contrib.sessions","django.contrib.sites",...
)ASGI_APPLICATION = "mysite.asgi.application"

注意:ASGI_APPLICATION 配置后正常可通过python manage.py runserver启动服务,低版本Django不行,Django 5.x 版本可行。

添加文件 myproject/asgi.py

from django.core.asgi import get_asgi_application
from django.urls import re_path# Initialize Django ASGI application early to ensure the AppRegistry
# is populated before importing code that may import ORM models.
django_asgi_app = get_asgi_application()from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
from channels.security.websocket import AllowedHostsOriginValidatorapplication = ProtocolTypeRouter({# 同时能支持原有http协议的接口"http": django_asgi_app,# 增加websocket协议的支持"websocket": AllowedHostsOriginValidator(AuthMiddlewareStack(# 接口路由URLRouter([re_path(r"^chat/(?P<room_name>\w+)/$", consumers.ChatConsumer.as_asgi()),]))),
})

WebSocket接口–消息接收者的实现

接口实现可以继承WebsocketConsumer / AsyncConsumer / AsyncConsumer,此处介绍WebsocketConsumer,代码示例:

class ChatConsumer(WebsocketConsumer):def connect(self):# django框架会自动处理websocket链接带上的headers信息进行鉴权认证,初始化成用户对象self.user = self.scope['user']self.accept()self.send(text_data="[Welcome %s!]" % self.user.username)def receive(self, *, text_data):if text_data.startswith("/name"):username = text_data[5:].strip()self.send(text_data="[set your username to %s]" % username)else:self.send(text_data=username + ": " + text_data)def disconnect(self, message):pass

值的一提的是,Django框架和Channels结合很好,Auth体系完全兼容,Django http中的header这里也能识别成User用户。

scope

Consumer接受到client端发来的websocket请求后,会将请求信息初始化成scope,请求相关信息可以从self.scope中获取,例如:

  • scope["client"] client来源ip和port, eg: ['127.0.0.1', 6533]
  • scope["user"] 根据headers等信息初始化的User用户
  • scope["path"] 请求接口path路径
  • scope["query_string"] 连接上的query参数
  • scope["headers"] 请求headers
  • scope["url_route"] 请求path定义路由解析出的参数,eg: {"args": {}, "kwargs": {"pk": 1}}

以上的介绍算是基本实现了一个简单的websoket服务。

若是实现较为复杂的群聊、或者广播通知该如何实现?下面 channel layer

通道层 channel layer

安装pip install channels_redis

通道层是一种通信系统。 它允许多个消费者实例相互通信以及与 Django 的其他部分通信。

通道层提供以下抽象:

  • 通道是一个可以发送消息的邮箱。 每个频道都有一个名称。 知道频道名称的任何人都可以向该频道发送消息。
  • 组是一组相关的通道。 一个团体有一个名字。 任何拥有群组名称的人都可以通过名称向群组添加/删除频道,并向群组中的所有频道发送消息。 不可能枚举特定组中有哪些频道。

每个消费者实例都有一个自动生成的唯一通道名称,因此可以通过通道层进行通信。

需要在Django settings.py 文件中添加配置

# Channels
ASGI_APPLICATION = "mysite.asgi.application"
CHANNEL_LAYERS = {"default": {"BACKEND": "channels_redis.core.RedisChannelLayer","CONFIG": {"hosts": [("127.0.0.1", 6379)],},},
}

接口代码实现

# chat/consumers.py
import jsonfrom asgiref.sync import async_to_sync
from channels.generic.websocket import WebsocketConsumerclass ChatConsumer(WebsocketConsumer):def connect(self):# 这里是将群名room_name定义在了path中,通过正则提取self.room_name = self.scope["url_route"]["kwargs"]["room_name"]self.room_group_name = f"chat_{self.room_name}"# Join room groupasync_to_sync(self.channel_layer.group_add)(self.room_group_name, self.channel_name)self.accept()def disconnect(self, close_code):# Leave room groupasync_to_sync(self.channel_layer.group_discard)(self.room_group_name, self.channel_name)# Receive message from WebSocketdef receive(self, text_data):text_data_json = json.loads(text_data)message = text_data_json["message"]# Send message to room groupasync_to_sync(self.channel_layer.group_send)(self.room_group_name, {"type": "chat.message", "message": message})# Receive message from room groupdef chat_message(self, event):message = event["message"]# Send message to WebSocketself.send(text_data=json.dumps({"message": message}))

部署

服务启动 daphne -b 0.0.0.0 -p 8000 myproject.asgi:application

其他参数可以查看 daphne文档 。

websocket协议nginx代理示例配置如下:

upstream channels-backend {server localhost:8000;
}
...
server {...location / {try_files $uri @proxy_to_app;}...location @proxy_to_app {proxy_pass http://channels-backend;proxy_http_version 1.1;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "upgrade";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 X-Forwarded-Host $server_name;}...
}

Web客户端连接

前端JS可以通过 WebSocket 实现连接,注意浏览器兼容问题即可。

// Create WebSocket connection.
const socket = new WebSocket("ws://localhost:8000/chat/room/");// Connection opened
socket.addEventListener("open", function (event) {socket.send("Hello Server!");
});// Listen for messages
socket.addEventListener("message", function (event) {console.log("Message from server ", event.data);
});

Mac客户端

借助工具 websocat , 可通过 brew install websocat 安装。

websocat ws://localhost:8000/chat/room/
# 加header
websocat -H="Authorization: Token xxxx" ws://localhost:8000/chat/room/

需要注意的是,-H=""中间等号不能用空格替代,否则无法生效,希望作者在之后的版本中个可以兼容这个问题。


  1. 可以关注下Django框架中提供的WSGI和ASGI的区别; ↩︎

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/18738.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C#学习备份

20190523 1、但当你创建了一个很大的类&#xff0c;那么为了方便创建对象&#xff0c;你最好使用var关键字。 2、类属性需要快速赋值 tsttab[] mytab new tsttab[] { new tsttab { ID 1, name “”, age 1 }, new tsttab { ID 1, name “”, age 2 } }; 3、 三层架构的各…

【java10】集合中新增copyof创建只读集合

在Java中&#xff0c;集合&#xff08;如List、Set、Map等&#xff09;是编程中常用的数据结构。然而&#xff0c;在某些场景下&#xff0c;我们可能希望集合中的数据是只读的&#xff0c;即不允许修改集合中的元素。在Java8及之前&#xff0c;要实现这样的功能&#xff0c;我们…

ScrumMaster认证机构及CSM、PSM、RSM价值比较

企业现有的经营管理模式和传统的瀑布式交付模式&#xff0c;已经不能适应快速变化的市场响应和客户需求&#xff0c;现代的敏捷工作方式在过去数年涌现&#xff0c;比如Scrum&#xff0c;XP&#xff0c;看板&#xff0c;DevOps等敏捷方法&#xff0c;近十年Scrum在国内企业中备…

[Leetcode LCR 106.判断二分图]

LCR 106. 判断二分图 - 力扣&#xff08;LeetCode&#xff09; 超时代码&#xff1a; class Solution {public:int work1[110] {0};int work2[110] {0};bool divide(vector<vector<int>>& graph, int n){bool judge false;if(n > graph.size()){for(in…

近200个幼儿启蒙简笔画含步骤图含音频

其实早就想搞一下简笔画的相关数据&#xff0c;但奈何几乎所有简笔画类的数据中的图片都有大大的水印&#xff0c;今天正好遇到一个启蒙简笔画的数据&#xff0c;好的地方是&#xff1a;简笔画步骤都是4步&#xff0c;步骤都有说明&#xff0c;步骤图片没有水印&#xff0c;每个…

怎么描述前端难点:深入探索与解析

怎么描述前端难点&#xff1a;深入探索与解析 在前端开发的广阔领域中&#xff0c;我们时常会遭遇各种挑战和难点。这些难点不仅源于技术的复杂性&#xff0c;还涉及到用户体验、性能优化等多个方面。那么&#xff0c;如何准确地描述前端难点呢&#xff1f;本文将从四个方面、…

ivySCI:最好的文献阅读管理软件!

ivySCI&#xff1a;最好的文献阅读管理软件 ivySCI比较强悍的点&#xff0c;推广介绍一下&#xff1a; 并不比Zotero差劲 &#x1f41f; 第一招&#xff1a;和Zotero一样&#xff0c;IvySci也能把你的文献宝贝们安排得明明白白。标签整理只是小菜一碟&#xff0c;它还能显示期…

C# 数字字符串排序

例如&#xff1a;string[] strings { "D10", "D2", "D1","D0", "D3", "D9" }; 升序后&#xff1a;strings { "D0", "D1", "D2","D3", "D9", "D10&quo…

chrome 浏览器历史版本下载

最近做一个项目,要使用到chrome浏览器比较久远的版本,在网上查找资源时,发现chrome比较老的版本的安装包特别难找,几经寻找,总算找到,具体方法如下 打开百度,搜索关键字【chrome版本号‘浏览迷’】&#xff0c;例如“chrome41浏览迷”&#xff0c;找到“全平台”开头的链接&am…

一款拥有15000+POC漏洞扫描工具

1 工具介绍 0x01 免责声明 请勿使用本文中所提供的任何技术信息或代码工具进行非法测试和违法行为。若使用者利用本文中技术信息或代码工具对任何计算机系统造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责。本文所提供的技术信息或代码工具仅供于学习&am…

【无标题】yoloV8目标检测与实例分割--目标检测onnx模型部署

1. 模型转换 ONNX Runtime 是一个开源的高性能推理引擎&#xff0c;用于部署和运行机器学习模型&#xff0c;其设计的目标是优化执行open neural network exchange &#xff08;onnx&#xff09;格式定义各模型&#xff0c;onnx是一种用于表示机器学习模型的开放标准。ONNX Ru…

深入分析 Android Activity (十)

文章目录 深入分析 Android Activity (十)1. Activity 的资源管理1.1 使用资源 ID 访问资源1.2 Drawable 资源1.3 使用 TypedArray 管理资源1.4 使用资源配置 2. Activity 的数据存储2.1 SharedPreferences2.2 文件存储2.3 SQLite 数据库2.4 ContentProvider 3. Activity 的性能…

一书读懂Python全栈安全,剑指网络空间安全

写在前面 通过阅读《Python全栈安全/网络空间安全丛书》&#xff0c;您将能够全面而深入地理解Python全栈安全的广阔领域&#xff0c;从基础概念到高级应用无一遗漏。本书不仅详细解析了Python在网络安全、后端开发、数据分析及自动化等全栈领域的安全实践&#xff0c;还紧密贴…

力扣刷题---409. 最长回文串【简单】

题目描述 给定一个包含大写字母和小写字母的字符串 s &#xff0c;返回 通过这些字母构造成的 最长的回文串 。 在构造过程中&#xff0c;请注意 区分大小写 。比如 “Aa” 不能当做一个回文字符串。 示例 1: 输入:s “abccccdd” 输出:7 解释: 我们可以构造的最长的回文串…

JVM的垃圾回收机制--GC

垃圾回收机制&#xff0c;是java提供的对于内存自动回收的机制。java不需要像C/C那样手动free()释放内存空间&#xff0c;而是在JVM中封装好了。垃圾回收机制&#xff0c;不是java独创的&#xff0c;现在应该是主流编程语言的标配。GC需要消耗额外的系统资源&#xff0c;而且存…

Java遍历Map集合的方法

Java中遍历Map集合的常用方式主要有以下几种&#xff1a; 1.使用keySet()方法遍历 遍历Map的key集合&#xff0c;然后通过key获取value。 Map<String, Integer> map new HashMap<>(); map.put("one", 1); map.put("two", 2); map.pu…

Flutter 中的 BaseLine 小部件:全面指南

Flutter 中的 BaseLine 小部件&#xff1a;全面指南 Flutter 提供了一系列布局小部件&#xff0c;使得开发者可以轻松地构建复杂且响应式的用户界面。Baseline 是这些小部件中的一个&#xff0c;它允许你根据基线对齐其子组件。这在需要精确控制文本或图形元素对齐时非常有用。…

Codeforces Round 946 (Div. 3) A~G

A.Phone Desktop (枚举) 题意&#xff1a; 小 A A A的手机有一个桌面&#xff08;或称启动器&#xff09;。桌面可以由多个屏幕组成。每个屏幕表示为大小为 5 3 5 \times 3 53 的网格&#xff0c;即五行三列。 有 x x x 个应用程序的图标大小为 1 1 1 \times 1 11 个单…

学前基础知识

1、Java版本&#xff1a; 1995年发布第一个版本&#xff0c;创始人gosling。 可知&#xff0c; JAVA8 和 JAVA11 为长期版本&#xff0c;其他均非长期版本&#xff0c;因此主流都在用 JAVA8 或 JAVA11。 2、Java技术体系平台&#xff1a; 3、Java重要特点 ①Java语言是面向对象…

C++无锁(lock free)队列moodycamel::ConcurrentQueue

moodycamel::ConcurrentQueue介绍 moodycamel::ConcurrentQueue一个用C++11实现的多生产者、多消费者无锁队列。 它具有以下特点: 1.快的让人大吃一惊,详见不同无锁队列之间的压测对比 2.单头文件实现,很容易集成到你的项目中 3.完全线程安全的无锁队列,支持任意线程数的并…