django+websocket

django-private-chat2 在线聊天室(django+websocket+nginx)

django-private-chat2是一个Django聊天应用程序,由 Django Channels、Websockets 和 Asyncio 提供支持,已经封装好了一些简单的聊天逻辑:包括 监听连接/断开 websocket,监听发送/接收 websocket消息,获取用户 对话框列表/消息列表等。
github地址:https://github.com/Bearle/django_private_chat2/
如果这个库够用直接按照说明使用即可。我这里因为要扩展实现自己的逻辑,所以自定义了一个模块chat。实现如下:

一.、准备工作:

(1)安装django:pip install django==3.2.20 django版本需要大于3.0,因为需要ASGI的支持;我这里使用的是3.2.20版本。

(2)安装channels:pip install channels==3.0.4 Channels 是一个采用 Django 并将其功能扩展到 HTTP 之外的项目,用于处理 WebSocket。

(3)安装channel-redis:pip install channels-redis==3.3.1 channels_redis是唯一支持生产使用的由 Django 维护的官方通道层。该层使用 Redis 作为后备存储,支持单服务器和分片配置以及组支持。

(4)安装django-private-chat2:pip install django-private-chat2==1.0.2

(5)安装daphne:pip install daphne==3.0.2 daphne将请求从客户端转发到 Django Channels 或其他ASGI应用,并将响应返回到客户端。

为什么需要使用daphne:
生产环境部署中,使用的是WSGI协议来启动的我们的项目,也就是使用的wsgi.py这个文件来对接的uWSGI服务器。但是channels使用的ASGI协议,在我们使用uWSGI来启动项目的时候,关于ASGI的一些配置他就找不到了。这就导致了所有的websocket请求都是404。
这个问题的解决有两种方案:
1)启用uWSGI来处理所有的http请求,另外开启一个daphne服务来处理websocket请求。这样的好处是按照请求类型分流,两种请求方式互不干扰。(亲测成功)
命令:daphne -p 4001 dingdang168.asgi:application
2)另外一种则是启用daphne服务来处理http和websocket这两种请求。在daphne服务内部他会根据请求类型的不同分开处理。让你既可以访问websocket又可以访问http。
这里采取第一种方法。

二、新增模块chat:

首先在项目根目录下执行:

python manage.py startapp chat

并依次执行以下步骤:

  • 将django-private-chat2下所有的目录文件copy到chat模块下。

  • 将chat模块下所有对django_private_chat2的引用改为chat。例如:
    from django_private_chat2.models 改为 from chat.models
    from django_private_chat2.serializers 改为 from chat.serializers

三、修改settings.py:

(1) 将channels和chat加入到INSTALLED_APPS里,并添加相应配置,如下所示:

INSTALLED_APPS = [
      #···,
      'daphne', # 放在比较靠前位置
      #···,
      'channels',  # channels应用
      'chat',  # chat模块
 ]

(2)设置ASGI应用:

ASGI_APPLICATION = '项目名称.asgi.application'

(3)设置通道层的通信后台:

CHANNEL_LAYERS = {
    # 开发环境
    # 'default': {
        #'BACKEND': 'channels.layers.InMemoryChannelLayer'
    # }
    # 生产环境
    'default': {
        'BACKEND': 'channels_redis.core.RedisChannelLayer',
        'CONFIG': {
            "hosts": ["redis://:password@127.0.0.1:6379/3"], # password改成自己的密码
        },
    }

四、新建asgi.py文件,与wsgi.py同级:

from django.core.asgi import get_asgi_application
django_asgi_app = get_asgi_application()
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
from chat import urls
application = ProtocolTypeRouter({
	# http请求
    "http": django_asgi_app,
    # websocket请求
    "websocket": AuthMiddlewareStack(
        URLRouter(urls.websocket_urlpatterns)
    ),
})

五、nginx配置文件中添加:

server{
# ···
 location /chat_ws {
	proxy_pass http://127.0.0.1:4001; # asgi的端口
	proxy_http_version 1.1;
	# 将http连接升级成websocket的连接。
	proxy_set_header Upgrade $http_upgrade;
	# 启用支持websocket连接
	proxy_set_header Connection "upgrade";
	# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
	# proxy_set_header X-Real-IP $remote_addr;
	}
# ···
}

六、重启相关服务:

  • 重启nginx:
    nginx -s reload #重新加载配置
  • 启动asgi服务:
    daphne -p 4001 项目名称.asgi:application

七、测试连接:

使用postman测试连接:
postman测试websocket连接

状态码101,表示websocket连接成功。

注意:

  1. 如果是在开发环境下,第五、六步骤可以直接省略,因为使用runserver命令启动时会直接启动asgi,如下图所示提示即表示启动成功。
    django启动asgi
  2. ws和wss的关系类似于HTTP和HTTPS。wss 表示在 TLS 之上的 Websocket。WSS提供了加密通信,而WS没有。
  3. 如果websocket请求需要传递额外的参数,例如token,可以放入请求头的Sec-WebSocket-Protocol中,用","隔开即可如果报错Error during WebSocket handshake: Sent non-empty ‘Sec-WebSocket-Protocol’ header but no response was received,意思是WebSocket握手阶段出错:发送了非空“Sec-WebSocket-Protocol”请求头但是响应中没有此字段
    解决方法:
    添加响应头Sec-WebSocket-Protocol,值设置为请求头Sec-WebSocket-Protocol的第一个协议
    将chat_consumer.py中的await self.accept()改为await self.accept(protocol[0])。

有错误或者遗漏的地方,欢迎指正交流!

参考链接:

  1. https://blog.csdn.net/qq_42902997/article/details/131558930

  2. https://blog.csdn.net/ZPeng_Yan/article/details/106198365

  3. https://channels.readthedocs.io/en/latest/introduction.html

  • 9
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Django中使用WebSocket实现系统消息通知可以通过以下步骤实现: 1. 安装Django Channels和asgiref ```bash pip install channels asgiref ``` 2. 创建一个Django应用程序 ```bash python manage.py startapp notifications ``` 3. 创建一个WebSocket路由 在`notifications`应用程序中创建一个`routing.py`文件,添加以下内容: ```python from django.urls import re_path from . import consumers websocket_urlpatterns = [ re_path(r'ws/notifications/$', consumers.NotificationConsumer.as_asgi()), ] ``` 4. 创建一个WebSocket消费者 在`notifications`应用程序中创建一个`consumers.py`文件,添加以下内容: ```python import asyncio import json from channels.consumer import AsyncConsumer from channels.db import database_sync_to_async from django.contrib.auth.models import User class NotificationConsumer(AsyncConsumer): async def websocket_connect(self, event): await self.send({ "type": "websocket.accept" }) user = self.scope["user"] if user.is_authenticated: await self.channel_layer.group_add( f"user_{user.id}", self.channel_name ) async def websocket_receive(self, event): user = self.scope["user"] if user.is_authenticated: data = json.loads(event["text"]) message = data["message"] await self.create_message(user, message) await self.channel_layer.group_send( f"user_{user.id}", { "type": "user.message", "message": message } ) async def websocket_disconnect(self, event): user = self.scope["user"] if user.is_authenticated: await self.channel_layer.group_discard( f"user_{user.id}", self.channel_name ) @database_sync_to_async def create_message(self, user, message): user = User.objects.get(id=user.id) user.notifications.create(message=message) ``` 5. 配置WebSocket路由 在`settings.py`文件中添加以下内容: ```python ASGI_APPLICATION = 'project_name.routing.application' CHANNEL_LAYERS = { "default": { "BACKEND": "channels.layers.InMemoryChannelLayer" } } ROOT_URLCONF = 'project_name.urls' INSTALLED_APPS = [ ... 'channels', 'notifications', ] ``` 6. 创建一个JavaScript文件 在`static/js/notifications.js`文件中添加以下内容: ```javascript var socket = new WebSocket("ws://" + window.location.host + "/ws/notifications/"); socket.onmessage = function(event) { var message = JSON.parse(event.data)["message"]; alert(message); } ``` 7. 在模板中引入JavaScript文件 在需要使用WebSocket的模板中添加以下内容: ```html {% load static %} <script src="{% static 'js/notifications.js' %}"></script> ``` 现在,当用户登录并连接到WebSocket时,他们将加入名为`user_<user_id>`的组。当用户收到新消息时,消息将保存到数据库中,并通过WebSocket发送到所有连接到该组的用户。在前端,我们使用JavaScript来处理接收到的消息,这里简单地使用了一个警报框来显示消息,你可以改为使用其他的UI库。 希望这个教程能够帮助你实现DjangoWebSocket的消息通知功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值