Django ASGI服务

1. ASGI简介

handlebars 复制代码
在Django中, ASGI(Asynchronous Server Gateway Interface)的引入使得Django应用能够支持异步编程.
从Django 3.0开始, Django就增加了对ASGI的支持, 但直到Django 3.1才正式推荐在生产环境中使用ASGI.
ASGI是一个用于Python的异步Web服务器的标准接口, 它允许你运行异步的Django应用.
handlebars 复制代码
要启动Django的ASGI服务器, 通常需要使用一个支持ASGI的服务器, 如Daphne, Uvicorn或Hypercorn.
以下是使用Uvicorn作为ASGI服务器来启动Django应用的基本步骤:
* 1. 确保Django版本: 首先, 确保Django版本是3.1或更高, 因为这些版本才正式支持ASGI.
* 2. 设置ASGI应用: 在Django项目的settings.py文件中, 确保已经设置了ASGI_APPLICATION变量,
     它应该指向项目中的asgi.py文件中的application对象.
python 复制代码
# settings.py  

# awsi配置
ASGI_APPLICATION = 'MyDjango.asgi.application'
# 这里的'your_project'是Django项目的名称.
handlebars 复制代码
* 3. 检查asgi.py: 在Django项目的根目录下, 有一个asgi.py文件.
     这个文件是Django自动生成的, 用于配置ASGI应用, 它通常看起来像这样:
python 复制代码
# asgi.py  
import os  
from django.core.asgi import get_asgi_application  

# 确保这个文件中的DJANGO_SETTINGS_MODULE环境变量正确设置为了项目设置模块.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'MyDjango.settings')  
 
application = get_asgi_application()
handlebars 复制代码
* 4. 安装ASGI服务器: 接下来, 需要安装一个ASGI服务器.
     以Uvicorn为例, 可以通过pip安装它: pip install uvicorn
handlebars 复制代码
* 5. 启动ASGI服务器: 最后, 使用Uvicorn(或其他ASGI服务器)来启动你的Django应用.
     在命令行中, 运行命令: uvicorn MyDajngo.asgi:application --host 0.0.0.0 --port 8000 .
     这里的'MyDajngo'是的Django项目的名称,
     --host 0.0.0.0表示服务器将监听所有可用的网络接口, --port 8000指定了服务器将使用的端口号.
     注意: 在settings.py文件中设置了ASGI_APPLICATION, 是不支持直接通过快捷键启动的, 因为runserver是基于WSGI的.
handlebars 复制代码
* 6. 访问应用: 现在, Django应用已经以异步方式在ASGI服务器上运行了.
     可以在浏览器中访问: http://127.0.0.1:8000 来查看应用.
handlebars 复制代码
由于ASGI是异步的, 需要修改视图和其他代码来利用异步编程的优势.
Django的ORM本身并不支持异步操作, 因此如果需要在异步视图中进行数据库操作, 
可能需要使用支持异步的数据库客户端库, 如databases或aiopg.

此外, 虽然ASGI为Django应用带来了异步编程的可能性, 但它并不是必需的.
如果应用不需要异步特性, 仍然可以像往常一样使用WSGI服务器(如Gunicorn或uWSGI)来运行你的Django应用.
handlebars 复制代码
Django的路由系统(URLs)和视图(Views)是以同步方式编写的, 即使使用ASGI来运行Django应用.
然而, 对于需要异步处理的功能, 如WebSocket连接和异步HTTP请求, 使用Django Channels是一个很好的解决方案.

2. Channels简介

handlebars 复制代码
Channels是一个允许编写异步消费者(consumers)的框架, 这些消费者可以处理WebSocket连接, 异步HTTP请求等.
Channels建立在ASGI之上, 允许编写真正的异步代码, 而不会阻塞Django的事件循环.
handlebars 复制代码
Channels提供了与Django路由系统相似的机制, 但它专注于异步操作.
在Channels中定义路由将不同的协议(如: HTTP, WebSocket)和路径映射到相应的异步消费者上.
handlebars 复制代码
以下是如何在Django项目中设置Channels的基本步骤:
* 1. 安装 Channels: pip install channels .
* 2. 修改项目的settings.py.
     将channels添加到INSTALLED_APPS中.
     设置ASGI_APPLICATION指向ASGI配置文件.
     由于Channels的功能依赖于Redis数据库, 因此还需要在settings.py中设置Channels的功能配置.
python 复制代码
# settings.py
INSTALLED_APPS = [  
    ...  
    'channels',
]

# ASGI配置
ASGI_APPLICATION = 'MyDjango.routing.application'

# Channels配置
CHANNEL_LAYERS = {
    'default': {
        'BACKEND': 'channels_redis.core.RedisChannelLayer',
        'CONFIG': {
            "hosts": [('127.0.0.1', 6379)],  # Redis配置
        },
    },
}
handlebars 复制代码
* 3. 执行数据迁移, 因为Channels需要使用Django内置的会话Session机制, 用于区分和识别每个用户的身份信息.
     执行: Python manage.py migrate .
handlebars 复制代码
* 4. 在应用中定义Channels路由.
     在应用目录下创建一个routing.py文件, 并定义WebSocket路由.
python 复制代码
# routing.py
from channels.auth import AuthMiddlewareStack  # 身份验证中间件堆栈
from channels.routing import ProtocolTypeRouter  # 协议类型路由器
from channels.routing import URLRouter  # URL 路由器
from .urls import websocket_urlpatterns  # websocket URL 模式

# 创建一个协议类型路由器实例, 并为其配置路由规则
application = ProtocolTypeRouter({
    # WebSocket协议使用身份验证中间件堆栈和URL路由器来处理
    # 默认情况下, 对于HTTP请求, Django 会自动将其路由到相应的视图函数或类
    'websocket': AuthMiddlewareStack(
        URLRouter(
            # 使用websocket_urlpatterns中的URL模式来路由WebSocket请求
            websocket_urlpatterns
        )
    ),
})
handlebars 复制代码
* 5. 设置WebSocket URL模式.
     在路由文件中定义WebSocket的URL模式.
python 复制代码
# MyDjango的urls.py
from django.urls import path, include
from .consumers import IndexConsumer

# 同步视图
urlpatterns = [
    path('', include(('index.urls', 'index'), namespace='index'))
]


# 异步视图
websocket_urlpatterns = [
    # 调用as_asgi()启动异步视图
    path('ws/index/', IndexConsumer.as_asgi()),
]
handlebars 复制代码
* 6. 编写消费者.
     在应用目录下创建一个consumers.py文件, 并编写异步消费者.
python 复制代码
# index/consumers.py
from channels.generic.websocket import AsyncWebsocketConsumer
import json


class IndexConsumer(AsyncWebsocketConsumer):

    # 连接
    async def connect(self):
        print("一个客户端连接了服务器")
        await self.accept()  # 接受传入套接字

    # 断开
    async def disconnect(self, close_code):
        print("一个客户端断开了连接")
        pass

    # 收到, 接收从 WebSocket 发送的消息
    async def receive(self, text_data=None, bytes_data=None):
        text_data_json = json.loads(text_data)  # 反序列化文本数据
        message = text_data_json['message']  # 取出聊天信息
        print(message)

        # 发送消息到 WebSocket
        await self.send(text_data=json.dumps({  # 序列化聊天信息
            'message': message
        }))
handlebars 复制代码
异步方法的调用机:
* connect()方法: 当WebSocket客户端尝试连接到服务器时, Channels会自动调用connect()方法.
  可以在这个方法中执行一些初始化操作, 比如验证客户端身份, 设置会话变量等, 并通过调用await self.accept()来接受连接.
* disconnect()方法: 当WebSocket连接关闭时, Channels会自动调用disconnect()方法.
  可以在这个方法中执行一些清理操作.
* receive()方法: 当WebSocket客户端发送消息到服务器时, Channels会自动调用receive()方法, 并将接收到的消息作为参数传递.
  需要在这个方法中处理接收到的消息, 并可能通过await self.send()或await self.send_json()等方法向客户端发送响应.

3. WebSocket介绍

handlebars 复制代码
在Django Channels中, WebSocket并不是通过传统的HTTP请求来访问的, 
因此不能直接通过浏览器地址栏(如输入:http://localhost:8000/ws/my-endpoint/)来访问WebSocket端点.

WebSocket是一种在单个TCP连接上进行全双工通讯的协议, 它允许服务器和客户端之间建立持久的连接, 并通过这个连接进行数据的双向传输.
handlebars 复制代码
浏览器可以通过JavaScript的WebSocket API来建立与WebSocket服务器的连接.
这个API允许创建一个WebSocket对象, 并指定要连接的URL.
注意, 这个URL应该以: ws://(非加密)或wss://(加密)开头, 而不是 http://或https://.
然后, 可以使用这个对象来发送和接收数据.
handlebars 复制代码
以下是一个简单的例子, 展示了如何在浏览器中使用JavaScript来连接WebSocket服务器:
* 1. 编写路由, 后续可以通过: 127.0.0.1:8000 , 触发index视图函数.
python 复制代码
# index/urls.pu
from django.urls import path
from .views import *

urlpatterns = [
    # 访问异步视图
    path('', index, name='index'),
]
handlebars 复制代码
* 2. 编写视图函数.
     在视图函数中放回一个模板页码.
handlebars 复制代码
* 3. 编写模板页面.
     在模块页面中编写js代码, 使用WebSocket API来建立与WebSocket服务器的连接.
html 复制代码
<!-- tempaltes的index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>访问异步视图</title>
</head>
<body>
<p>访问: 异步视图...</p>
<script>
    // 生成一个WebSocket对象
    var chatSocket = new WebSocket('ws://' + window.location.host + '/ws/index/');

    // 监听连接打开事件
    chatSocket.onopen = function (event) {
        console.log('WebSocket连接成功');
        // 连接建立后发送消息
        chatSocket.send(JSON.stringify({
            'message': '你好!'
        }));
    };

    // 接收信息
    chatSocket.onmessage = function (e) {
        try {
            var data = JSON.parse(e.data);
            var message = data['message'];
            alert(message);
        } catch (error) {
            console.error('解析消息时出错:', error);
        }
    };

    // 处理连接关闭事件
    chatSocket.onclose = function (event) {
        if (event.wasClean) {
            console.log('WebSocket连接正常关闭');
        } else {
            console.error('WebSocket连接异常关闭');
        }
        console.log('关闭代码:', event.code, '关闭原因:', event.reason);
    };

    // 处理连接错误事件
    chatSocket.onerror = function (error) {
        console.error('WebSocket发生错误:', error);
    };
</script>
</body>
</html>
handlebars 复制代码
* 4. 启动项目(因为在应用列表中注册了Channels, 所以支持直接启动), 访问: 127.0.0.1:8000 , 执行index视图函数.
     视图函数返回的页面会执行js代码先访问: ws://127.0.0.0:8000/ws/index/ , 执行异步视图.
handlebars 复制代码
结论: 通过Django Channels, 可以编写异步的WebSocket消费者和其他类型的异步协议处理器, 从而充分利用ASGI的优势.
虽然Django的路由系统(URLs)和视图(Views)主要用于同步操作, 但Channels提供了与Django路由相似的机制, 专门用于异步操作.
相关推荐
qq_4330994043 分钟前
Ubuntu20.04从零安装IsaacSim/IsaacLab
数据库
Dlwyz1 小时前
redis-击穿、穿透、雪崩
数据库·redis·缓存
工业甲酰苯胺3 小时前
Redis性能优化的18招
数据库·redis·性能优化
没书读了4 小时前
ssm框架-spring-spring声明式事务
java·数据库·spring
i道i4 小时前
MySQL win安装 和 pymysql使用示例
数据库·mysql
小怪兽ysl4 小时前
【PostgreSQL使用pg_filedump工具解析数据文件以恢复数据】
数据库·postgresql
wqq_9922502775 小时前
springboot基于微信小程序的食堂预约点餐系统
数据库·微信小程序·小程序
爱上口袋的天空5 小时前
09 - Clickhouse的SQL操作
数据库·sql·clickhouse
聂 可 以6 小时前
Windows环境安装MongoDB
数据库·mongodb
web前端神器6 小时前
mongodb多表查询,五个表查询
数据库·mongodb