【Sanic 框架 / 1】深入学习:从入门到进阶

文章目录

一、基础知识学习(入门)

Sanic 简介

Sanic 是一个基于 Python 的异步 Web 框架,它使用 Python 的 asyncio 库实现高效的异步请求处理,适合高并发环境下的 Web 应用开发。Sanic 的设计理念是轻量级且高性能,特别适用于需要处理大量并发请求的应用,比如实时聊天、推送通知、API 服务等。

与传统的同步 Web 框架相比,Sanic 利用异步特性,通过 asyncawait 语法大幅提升了 Web 服务的响应能力,能够同时处理多个 I/O 密集型任务,而不会阻塞服务器的主线程。

什么是 Sanic 框架?

Sanic 是一个用 Python 编写的 Web 框架,专注于高性能和异步编程。它允许开发者通过异步的方式处理 HTTP 请求,从而提高并发性能。Sanic 完全支持 Python 3.7 及以上版本,并且支持 async/await 语法,使得编写高并发、实时通信和长连接等服务变得更加简单高效。

与其他 Web 框架(如 Flask 或 Django)相比,Sanic 的主要特点是其内置的异步支持,它可以在一个请求的生命周期内并行处理多个 I/O 操作。这使得 Sanic 在面对高并发或实时数据更新的场景时,比传统框架表现出更高的性能。

Sanic 的优势和适用场景

1. 高性能

Sanic 利用异步非阻塞 I/O 和 asyncio 协程,能够大幅提升并发请求的处理效率。相比于传统的同步框架,Sanic 能够在处理大量并发连接时,保持高效且稳定。

2. 异步支持

Sanic 本质上是异步的框架,使用 asyncawait 语法来处理请求和响应。对于网络请求、数据库操作和文件 I/O 等耗时操作,Sanic 能够高效并发执行,而不会阻塞主线程。

3. 简洁易用

Sanic 提供了简单直观的 API,开发者可以快速上手。无论是新手还是经验丰富的开发者,都能通过简洁的语法和易于理解的文档快速构建 Web 应用。

4. WebSocket 支持

Sanic 内置对 WebSocket 的支持,适合实时聊天、实时通知、推送等应用场景,能够处理持续的双向通信。

5. 灵活扩展

Sanic 提供了蓝图(Blueprint)和中间件支持,方便开发者模块化管理代码,并对请求生命周期进行控制。可以轻松集成数据库、缓存、日志等第三方服务,满足不同的业务需求。

适用场景:

  • 高并发 Web API 服务
  • 实时聊天应用
  • 推送通知系统
  • IoT(物联网)系统
  • 数据流和实时分析服务

环境搭建

在开始使用 Sanic 开发应用之前,首先需要搭建开发环境。

1. 安装 Python(3.7 及以上版本)

Sanic 支持 Python 3.7 及以上版本。如果尚未安装 Python,可以访问 Python 官网 下载并安装。

在终端中检查 Python 版本:

bash 复制代码
python --version

确保安装的是 Python 3.7 或更高版本。

2. 创建虚拟环境

为了避免与系统其他项目的依赖冲突,建议使用 Python 的虚拟环境管理工具(如 venvvirtualenv)来为项目创建一个独立的环境。

使用 venv 创建虚拟环境的步骤:

bash 复制代码
python -m venv sanic_env

激活虚拟环境:

  • 在 Linux/macOS 上:

    bash 复制代码
    source sanic_env/bin/activate
  • 在 Windows 上:

    bash 复制代码
    .\sanic_env\Scripts\activate

激活虚拟环境后,可以在这个环境中安装所有依赖,不会影响系统的其他 Python 项目。

3. 安装 Sanic

安装 Sanic 框架,只需要运行以下命令:

bash 复制代码
pip install sanic

安装完成后,可以在 Python 环境中通过 import sanic 测试是否安装成功。

第一个 Sanic 应用

现在,我们开始编写第一个简单的 Sanic 应用,它会在访问根路径时返回一条简单的 JSON 消息。

1. 创建应用文件

在项目目录下,创建一个新的 Python 文件,比如 app.py,然后添加以下代码:

python 复制代码
from sanic import Sanic
from sanic.response import json

# 创建一个 Sanic 实例
app = Sanic("HelloWorldApp")

# 创建路由,处理根路径请求
@app.route("/")
async def hello(request):
    return json({"message": "Hello, Sanic!"})

# 运行应用
if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8000)

2. 理解 app.run() 的参数配置

app.run() 方法用于启动 Sanic 应用,它接受多个参数来配置应用的运行方式。常用参数如下:

  • host :指定应用的主机地址,默认为 127.0.0.1(即本机地址)。设置为 "0.0.0.0" 可以让应用对外开放,允许其他设备访问。
  • port :指定应用监听的端口号,默认为 8000。可以根据需要修改为其他端口。
  • debug :如果设置为 True,将在开发过程中启用调试模式,方便调试和查看错误信息。默认情况下,开发模式是启用的。

3. 启动应用

在终端中,进入 app.py 所在的目录,并运行以下命令启动应用:

bash 复制代码
python app.py

会看到类似如下的信息,表示应用已启动:

[2025-01-13 00:00:00 +0000] [1234] [INFO] Sanic: Sanic version 22.6.0
[2025-01-13 00:00:00 +0000] [1234] [INFO] Goin' Fast @ http://0.0.0.0:8000

4. 访问应用

打开浏览器,访问 http://127.0.0.1:8000/,会看到返回的 JSON 响应:

json 复制代码
{
  "message": "Hello, Sanic!"
}

二、核心概念与 API 学习

路由

路由的定义和动态参数处理

在 Sanic 中,路由用于定义请求的 URL 路径和处理函数之间的映射关系。通过装饰器的形式,将函数与路由路径绑定,当访问指定路径时,Sanic 会调用相应的处理函数。

最基础的路由定义方式如下:

python 复制代码
@app.route("/hello")
async def hello(request):
    return json({"message": "Hello, Sanic!"})

此外,Sanic 支持动态路由参数,可以通过路径中的占位符定义动态参数。例如:

python 复制代码
@app.route("/user/<user_id>")
async def get_user(request, user_id):
    return json({"user_id": user_id})

在上面的例子中,<user_id> 是动态参数,Sanic 会提取 URL 中的值并将其传递给路由处理函数。

路由匹配规则和方法(GETPOSTPUTDELETE 等)

Sanic 支持多种 HTTP 方法(如 GETPOSTPUTDELETE)的路由定义。默认情况下,路由会匹配 GET 请求,但可以显式地指定 HTTP 方法。

例如,定义 POST 请求路由:

python 复制代码
@app.route("/login", methods=["POST"])
async def login(request):
    data = request.json  # 获取 JSON 数据
    return json({"status": "success", "data": data})

同样,也可以定义多个方法的路由:

python 复制代码
@app.route("/user/<user_id>", methods=["GET", "PUT"])
async def user_info(request, user_id):
    if request.method == "GET":
        return json({"user_id": user_id, "action": "get"})
    elif request.method == "PUT":
        return json({"user_id": user_id, "action": "update"})

Sanic 会根据请求方法自动调用相应的路由处理函数。

请求与响应

request 对象的属性(argsformjsonheaders 等)

Sanic 的 request 对象提供了丰富的属性来获取请求中的各种数据:

  • args :获取查询参数。例如,/search?q=python 中,q 可以通过 request.args.get("q") 获取。
  • form :获取表单数据。对于 POST 请求中的表单数据,可以使用 request.form
  • json :如果请求体是 JSON 格式的数据,可以使用 request.json 来获取。
  • headers :访问请求头部信息。例如,request.headers["User-Agent"] 获取用户代理。
python 复制代码
@app.route("/search", methods=["GET"])
async def search(request):
    query = request.args.get("q", "")
    return json({"query": query})

@app.route("/login", methods=["POST"])
async def login(request):
    form_data = request.form
    return json({"status": "success", "data": form_data})

response 对象的生成方法(json()text()html() 等)

Sanic 的 response 对象提供了多种方法来生成不同类型的响应:

  • json():返回 JSON 格式的响应。
  • text():返回纯文本格式的响应。
  • html():返回 HTML 格式的响应。
python 复制代码
@app.route("/json")
async def json_response(request):
    return json({"message": "This is a JSON response"})

@app.route("/text")
async def text_response(request):
    return text("This is a plain text response")

@app.route("/html")
async def html_response(request):
    return html("<h1>This is an HTML response</h1>")

这些方法会自动设置合适的 Content-Type 头,确保客户端能够正确解析响应数据。

中间件

中间件的定义与应用(requestresponse 阶段)

中间件是处理请求和响应的钩子函数,它们在请求到达路由之前和响应返回客户端之前执行。Sanic 支持两种类型的中间件:

  • 请求中间件:在请求被路由处理前执行。
  • 响应中间件:在响应返回客户端前执行。

定义中间件的方式如下:

python 复制代码
from sanic import Sanic
from sanic.response import json

app = Sanic("MiddlewareExample")

# 请求中间件
@app.middleware("request")
async def add_request_id(request):
    request["request_id"] = "12345"

# 响应中间件
@app.middleware("response")
async def add_custom_header(request, response):
    response.headers["X-Custom-Header"] = "This is a custom header"
    return response

@app.route("/")
async def index(request):
    return json({"message": "Hello with Middleware!"})

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8000)

使用中间件进行日志记录或验证请求

中间件非常适合用于日志记录、请求验证、身份验证等任务。例如,可以在请求阶段记录日志,或者在响应阶段修改返回的内容:

python 复制代码
@app.middleware("request")
async def log_request(request):
    print(f"Incoming request: {request.method} {request.path}")

异步处理

Python 异步编程基础(async/await 的使用)

Sanic 的最大特点之一就是异步处理请求。可以在路由处理函数中使用 asyncawait,让函数变为异步执行,从而提高并发性能。

  • async:用于定义异步函数。
  • await:用于等待异步操作的结果。

例如,使用 asyncawait 来模拟一个耗时操作:

python 复制代码
@app.route("/long_task")
async def long_task(request):
    await asyncio.sleep(5)  # 模拟耗时任务
    return json({"message": "Task completed"})

Sanic 会在等待 asyncio.sleep(5) 时不阻塞其他请求,充分利用异步特性。

异步任务的实现与调度

在 Sanic 中,可以使用 asyncio 来调度异步任务。例如,使用后台任务执行耗时操作:

python 复制代码
import asyncio

@app.route("/start_task")
async def start_task(request):
    asyncio.create_task(long_running_task())
    return json({"message": "Task started!"})

async def long_running_task():
    await asyncio.sleep(10)
    print("Task finished")

蓝图(Blueprints)

理解蓝图的概念和用途

蓝图是 Sanic 中用于组织应用代码的工具,它允许将路由和视图函数分组,以便于模块化开发。通过蓝图,可以将一个大型应用拆分成多个小的模块。

例如,创建一个蓝图并在应用中注册:

python 复制代码
from sanic import Blueprint

# 创建蓝图
bp = Blueprint("user")

@bp.route("/profile")
async def profile(request):
    return json({"message": "User Profile"})

# 注册蓝图
app.blueprint(bp)

如何使用蓝图进行模块化开发

通过使用蓝图,可以将不同功能的路由分别放在不同的文件中,实现模块化管理。例如,将用户相关的路由放在 user.py 文件中,产品相关的路由放在 product.py 中。

python 复制代码
# user.py
from sanic import Blueprint

bp = Blueprint("user")

@bp.route("/profile")
async def profile(request):
    return json({"message": "User Profile"})

# main.py
from sanic import Sanic
from user import bp

app = Sanic("ModularApp")
app.blueprint(bp)

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8000)

异常处理

捕获全局异常

Sanic 允许全局捕获异常并进行自定义处理。可以使用 @app.exception 装饰器来捕获全局异常:

python 复制代码
@app.exception(Exception)
async def handle_exception(request, exception):
    return json({"error": str(exception)}, status=500)

自定义异常处理方法

也可以定义特定的异常处理函数,根据不同的错误类型做不同的处理。例如,处理 404 错误时返回自定义页面:

python 复制代码
@app.exception(NotFound)
async def handle_not_found(request, exception):
    return html("<h1>Page Not Found</h1>", status=404)

三、进阶功能与性能优化

WebSocket 支持

实现 WebSocket 通信的简单服务

WebSocket 是一种在客户端和服务器之间建立全双工通信的协议,允许服务器和客户端之间实时双向传输数据。Sanic 提供了对 WebSocket 的原生支持,使用 @app.websocket() 装饰器可以轻松实现 WebSocket 服务。

以下是一个简单的 WebSocket 示例:

python 复制代码
@app.websocket('/ws')
async def websocket_handler(request, ws):
    while True:
        message = await ws.recv()  # 接收消息
        print(f"Received message: {message}")
        await ws.send(f"Echo: {message}")  # 发送回显消息

在此代码中,客户端发送的消息会被服务器接收到,并通过 ws.send() 返回给客户端,实现了基本的 WebSocket 双向通信。

处理实时消息与广播功能

除了基本的回显功能,WebSocket 还可以用于实现实时消息推送或广播。例如,当一个客户端发送消息时,其他所有连接的客户端也能收到该消息:

python 复制代码
sockets = []  # 存储 WebSocket 连接

@app.websocket('/ws')
async def websocket_handler(request, ws):
    sockets.append(ws)
    try:
        while True:
            message = await ws.recv()
            for socket in sockets:
                if socket != ws:  # 不广播给发送者
                    await socket.send(message)
    except:
        sockets.remove(ws)  # 断开连接时移除

在这个例子中,服务器会将每个客户端发送的消息广播给其他所有客户端,从而实现了实时通信功能。

文件上传与下载

实现文件上传接口

Sanic 提供了 request.files 来处理文件上传。可以通过 POST 请求上传文件,并将其保存到服务器本地。

python 复制代码
@app.route('/upload', methods=["POST"])
async def upload_file(request):
    file = request.files.get('file')  # 获取上传的文件
    if file:
        with open(f"./uploads/{file.name}", 'wb') as f:
            f.write(file.body)  # 将文件内容写入磁盘
        return json({"status": "success", "filename": file.name})
    return json({"status": "fail", "message": "No file uploaded"})

此代码将上传的文件保存到服务器的 uploads/ 文件夹,并返回上传文件的文件名。

提供文件下载服务

Sanic 通过 send_file() 方法支持文件下载。可以根据文件路径返回文件给客户端:

python 复制代码
from sanic.response import send_file

@app.route('/download/<filename>', methods=["GET"])
async def download_file(request, filename):
    file_path = f"./uploads/{filename}"
    return await send_file(file_path)

客户端可以访问 /download/<filename> 来下载指定的文件。send_file 会自动处理文件传输,支持流式传输,适合大文件下载。

中间件

中间件的定义与应用(requestresponse 阶段)

中间件是处理请求和响应的钩子函数,它们在请求到达路由之前和响应返回客户端之前执行。Sanic 支持两种类型的中间件:

  • 请求中间件:在请求被路由处理前执行。
  • 响应中间件:在响应返回客户端前执行。

定义中间件的方式如下:

python 复制代码
from sanic import Sanic
from sanic.response import json

app = Sanic("MiddlewareExample")

# 请求中间件
@app.middleware("request")
async def add_request_id(request):
    request["request_id"] = "12345"

# 响应中间件
@app.middleware("response")
async def add_custom_header(request, response):
    response.headers["X-Custom-Header"] = "This is a custom header"
    return response

@app.route("/")
async def index(request):
    return json({"message": "Hello with Middleware!"})

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8000)

使用中间件进行日志记录或验证请求

中间件非常适合用于日志记录、请求验证、身份验证等任务。例如,可以在请求阶段记录日志,或者在响应阶段修改返回的内容:

python 复制代码
@app.middleware("request")
async def log_request(request):
    print(f"Incoming request: {request.method} {request.path}")

异步处理

Python 异步编程基础(async/await 的使用)

Sanic 的最大特点之一就是异步处理请求。可以在路由处理函数中使用 asyncawait,让函数变为异步执行,从而提高并发性能。

  • async:用于定义异步函数。
  • await:用于等待异步操作的结果。

例如,使用 asyncawait 来模拟一个耗时操作:

python 复制代码
@app.route("/long_task")
async def long_task(request):
    await asyncio.sleep(5)  # 模拟耗时任务
    return json({"message": "Task completed"})

Sanic 会在等待 asyncio.sleep(5) 时不阻塞其他请求,充分利用异步特性。

异步任务的实现与调度

在 Sanic 中,可以使用 asyncio 来调度异步任务。例如,使用后台任务执行耗时操作:

python 复制代码
import asyncio

@app.route("/start_task")
async def start_task(request):
    asyncio.create_task(long_running_task())
    return json({"message": "Task started!"})

async def long_running_task():
    await asyncio.sleep(10)
    print("Task finished")

蓝图(Blueprints)

理解蓝图的概念和用途

蓝图是 Sanic 中用于组织应用代码的工具,它允许将路由和视图函数分组,以便于模块化开发。通过蓝图,可以将一个大型应用拆分成多个小的模块。

例如,创建一个蓝图并在应用中注册:

python 复制代码
from sanic import Blueprint

# 创建蓝图
bp = Blueprint("user")

@bp.route("/profile")
async def profile(request):
    return json({"message": "User Profile"})

# 注册蓝图
app.blueprint(bp)

如何使用蓝图进行模块化开发

通过使用蓝图,可以将不同功能的路由分别放在不同的文件中,实现模块化管理。例如,将用户相关的路由放在 user.py 文件中,产品相关的路由放在 product.py 中。

python 复制代码
# user.py
from sanic import Blueprint

bp = Blueprint("user")

@bp.route("/profile")
async def profile(request):
    return json({"message": "User Profile"})

# main.py
from sanic import Sanic
from user import bp

app = Sanic("ModularApp")
app.blueprint(bp)

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8000)

异常处理

捕获全局异常

Sanic 允许全局捕获异常并进行自定义处理。可以使用 @app.exception 装饰器来捕获全局异常:

python 复制代码
@app.exception(Exception)
async def handle_exception(request, exception):
    return json({"error": str(exception)}, status=500)

自定义异常处理方法

也可以定义特定的异常处理函数,根据不同的错误类型做不同的处理。例如,处理 404 错误时返回自定义页面:

python 复制代码
@app.exception(NotFound)
async def handle_not_found(request, exception):
    return html("<h1>Page Not Found</h1>", status=404)

相关推荐
mnwl12_039 分钟前
python轻量级框架-flask
开发语言·python·flask
张小特43 分钟前
flask项目中使用schedule定时任务案例
后端·python·flask
gf13211111 小时前
python_在钉钉群@人员发送消息
android·python·钉钉
B站计算机毕业设计超人1 小时前
计算机毕业设计PySpark+Hadoop+Hive机票预测 飞机票航班数据分析可视化大屏 航班预测系统 机票爬虫 飞机票推荐系统 大数据毕业设计
大数据·hadoop·爬虫·python·spark·课程设计·数据可视化
xianfianpan2 小时前
史上最简单open-webui安装方式!!!
python·深度学习·神经网络·ai
我们的五年2 小时前
【C++课程学习】:C++中的IO流(istream,iostream,fstream,sstream)
linux·c++·学习
Ronin-Lotus2 小时前
嵌入式硬件篇---基本组合逻辑电路
stm32·单片机·嵌入式硬件·学习·信息可视化
Ronin-Lotus2 小时前
嵌入式硬件篇---PID控制
单片机·嵌入式硬件·mcu·学习·程序人生·算法·硬件工程
deephub2 小时前
Python时间序列分析:使用TSFresh进行自动化特征提取
python·机器学习·时间序列·特征提取
brilliantgby2 小时前
蓝桥杯3527阶乘的和 | 组合数学
python·蓝桥杯