[Python3] Sanic中间件

Sanic 中,中间件(middleware)是指在请求和响应之间执行的代码。它们是一个非常强大的工具,用于处理请求的预处理、响应的后处理、全局错误处理、日志记录、认证、权限校验、跨域资源共享(CORS)等任务。中间件通常用于应用程序的全局逻辑,在请求处理前或响应处理后执行。

在这里插入图片描述

Sanic 中间件的工作流程

Sanic 中间件会在以下两个阶段执行:

  1. 请求处理前:处理请求数据,在请求被路由处理之前执行。可以用于校验、修改请求等操作。
  2. 响应处理后:处理响应数据,在响应被发送给客户端之前执行。可以用于修改响应、记录日志等操作。

中间件的使用

Sanic 中,中间件通过装饰器来定义。你可以为整个应用程序(全局中间件)定义中间件,也可以为某些特定的路由定义中间件。

1. 全局中间件

全局中间件是在整个应用程序的生命周期中被调用的,不依赖于特定的路由。它们在请求和响应的各个阶段都会执行。

请求阶段的全局中间件

全局中间件通常用于处理请求的预处理,如身份验证、记录日志、设置 CORS 等。

from sanic import Sanic
from sanic.response import json

app = Sanic("MyApp")

# 请求阶段的全局中间件
@app.middleware("request")
async def log_request(request):
    print(f"Request received: {request.method} {request.url}")
    # 你可以在这里对请求进行修改,例如身份验证、设置 CORS 等
    # 如果请求需要认证,可以在这里进行验证

# 响应阶段的全局中间件
@app.middleware("response")
async def log_response(request, response):
    print(f"Response status: {response.status}")
    # 你可以在这里修改响应,例如添加 CORS 头部、记录日志等
    # 在响应返回给客户端之前处理
    response.headers['X-Custom-Header'] = 'Sanic'  # 可以修改响应头
    return response

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

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

在这个例子中:

  • log_request 中间件会在每个请求到达应用时被调用,打印请求的方法和 URL。
  • log_response 中间件会在每个响应返回给客户端之前被调用,打印响应的状态码,并在响应头中添加一个自定义的 header。

2. 路由中间件

你还可以为特定的路由或路由组定义中间件。这是 Sanic 提供的灵活性,可以让你为某些路由添加额外的逻辑,而不影响其他路由。

@app.middleware("request", route="/user/<user_id>")
async def check_user_auth(request, user_id):
    # 假设我们通过 header 进行身份验证
    if request.headers.get("Authorization") != "Bearer my_token":
        return json({"error": "Unauthorized"}, status=401)
    print(f"Authenticated request for user {user_id}")

在这个示例中,check_user_auth 中间件只会在访问 /user/<user_id> 路由时执行,检查请求头中的 Authorization 字段是否包含有效的 Token。

3. 异常处理中间件

Sanic 中的异常处理中间件允许你捕获应用程序中的未处理异常,并为用户提供定制化的错误信息。

你可以使用 @app.exception 装饰器捕获特定类型的异常,也可以使用中间件全局处理错误。

捕获特定异常
from sanic.exceptions import SanicException

@app.exception(SanicException)
async def handle_sanic_exception(request, exception):
    return json({"error": f"Sanic error: {exception}"}, status=500)
捕获所有异常

你也可以定义一个捕获所有异常的全局中间件,并返回自定义的错误信息。

@app.middleware("response")
async def handle_all_exceptions(request, response):
    if hasattr(request, 'exception') and request.exception:
        return json({"error": f"Unhandled error: {request.exception}"}, status=500)
    return response

在这个例子中,如果某个请求抛出了异常,并且没有被其他中间件捕获,handle_all_exceptions 会捕获到并返回一个自定义的错误响应。

4. 异步中间件

由于 Sanic 是基于 asyncio 的异步框架,你可以编写异步的中间件,这样它们不会阻塞事件循环。中间件是异步的,这意味着你可以执行 I/O 操作(例如数据库查询或 HTTP 请求)而不会阻塞其他请求的处理。

@app.middleware("request")
async def async_middleware(request):
    # 异步操作,例如异步查询数据库
    await asyncio.sleep(1)
    print("Async operation completed")

5. 优先级和中间件顺序

多个中间件会按照定义的顺序依次执行。在 Sanic 中,中间件的优先级是固定的,按照以下顺序执行:

  • 请求中间件:按定义的顺序执行,最先定义的请求中间件最先执行。
  • 响应中间件:按定义的顺序执行,最先定义的响应中间件最先执行。

6. 中间件的运行机制

请求阶段

请求阶段中间件是指那些在请求路由匹配之前执行的中间件,通常用于请求预处理,例如请求数据解析、验证、认证等。

响应阶段

响应阶段的中间件是在响应发送回客户端之前执行的,通常用于对响应进行修改,例如添加额外的响应头、修改响应数据等。

7. 使用中间件进行身份验证

在 Web 开发中,身份验证是非常常见的需求。可以使用中间件来实现身份验证逻辑。比如,检查用户请求头中的 Token 或 Cookies 是否有效。

@app.middleware("request")
async def check_auth(request):
    token = request.headers.get("Authorization")
    if token != "Bearer valid_token":
        return json({"error": "Unauthorized"}, status=401)

8. 使用中间件实现 CORS

跨域资源共享(CORS)是一种允许服务器控制哪些域可以访问其资源的机制。你可以使用中间件来添加 CORS 头部。

@app.middleware("response")
async def add_cors_headers(request, response):
    response.headers["Access-Control-Allow-Origin"] = "*"
    response.headers["Access-Control-Allow-Methods"] = "GET, POST, OPTIONS"
    response.headers["Access-Control-Allow-Headers"] = "Content-Type, Authorization"
    return response

9. 中间件的多个装饰器

Sanic 支持多个中间件装饰器应用在同一个请求或响应阶段上。例如,你可以同时应用多个请求中间件。

@app.middleware("request")
async def middleware_one(request):
    print("Middleware one executed")

@app.middleware("request")
async def middleware_two(request):
    print("Middleware two executed")

在这个例子中,middleware_one 会先执行,然后是 middleware_two

总结

Sanic 中的中间件是非常强大和灵活的,它们使得你能够在 Web 应用的请求处理流程中插入自定义逻辑。中间件的使用场景非常广泛,包括请求和响应处理、身份验证、权限控制、日志记录、CORS 处理、错误处理等。

主要特点:
  • 请求中间件:在请求路由处理之前执行。
  • 响应中间件:在响应返回给客户端之前执行。
  • 全局中间件:适用于整个应用。
  • 路由中间件:只适用于特定的路由。
  • 异步操作:支持异步中间件,可以执行 I/O 操作而不会阻塞事件循环。

通过合理使用中间件,你可以在 Sanic 应用中灵活地处理各种需求,提高代码的可维护性和扩展性。


统计每个请求耗时

要统计一个请求的执行时间,你可以利用 Sanic 中间件来实现。在请求处理的生命周期中,我们可以在请求开始时记录时间戳,在请求结束时计算并输出请求的执行时间。

1. 使用中间件统计请求执行时间

我们可以使用 请求中间件 来记录每个请求开始时的时间戳,然后使用 响应中间件 来计算并输出请求的执行时间。

示例代码
from sanic import Sanic
from sanic.response import json
import time

app = Sanic("TimingApp")

# 请求中间件:记录请求开始的时间
@app.middleware("request")
async def record_start_time(request):
    request.ctx.start_time = time.time()  # 将开始时间存储到请求上下文中

# 响应中间件:计算并输出请求执行时间
@app.middleware("response")
async def calculate_execution_time(request, response):
    if hasattr(request.ctx, 'start_time'):
        end_time = time.time()
        execution_time = end_time - request.ctx.start_time  # 计算执行时间
        print(f"Request to {request.url} took {execution_time:.4f} seconds")
    return response

# 示例路由
@app.route("/")
async def hello(request):
    return json({"message": "Hello, Sanic!"})

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

2. 代码解析

  1. record_start_time 请求中间件

    • 在请求到达应用时触发,使用 time.time() 获取当前时间并将其存储在 request.ctx.start_time 中。ctxSanic 提供的上下文对象,用来在请求的生命周期内存储数据。
  2. calculate_execution_time 响应中间件

    • 在请求完成后触发,计算请求执行的时间。通过 time.time() 获取当前时间,并与 request.ctx.start_time 进行比较,得到请求的执行时间。
    • 输出请求的执行时间,单位是秒。
  3. 示例路由

    • / 路由中,我们返回一个简单的 JSON 响应,测试请求执行时间的统计。

3. 测试

当你运行上面的代码并访问 http://localhost:8000/ 时,终端输出类似以下内容:

Request to / took 0.0023 seconds

这表示请求到 / 的执行时间是 0.0023 秒。

4. 更复杂的统计方法

如果你需要更精细的控制(例如,统计多个请求的平均执行时间、最慢的请求、最短的请求等),你可以进一步扩展这个功能,记录统计数据到日志文件或者数据库中。

例如,你可以将执行时间记录到一个全局的统计数据中:

import time
from sanic import Sanic
from sanic.response import json
from collections import defaultdict

app = Sanic("TimingApp")
request_stats = defaultdict(list)  # 用于存储每个路由的执行时间

# 请求中间件:记录请求开始的时间
@app.middleware("request")
async def record_start_time(request):
    request.ctx.start_time = time.time()

# 响应中间件:计算请求执行时间并保存
@app.middleware("response")
async def calculate_execution_time(request, response):
    if hasattr(request.ctx, 'start_time'):
        end_time = time.time()
        execution_time = end_time - request.ctx.start_time
        print(f"Request to {request.url} took {execution_time:.4f} seconds")
        request_stats[request.url].append(execution_time)  # 记录执行时间

    return response

# 获取平均执行时间的路由
@app.route("/stats")
async def stats(request):
    stats = {url: sum(times) / len(times) for url, times in request_stats.items()}
    return json(stats)

# 示例路由
@app.route("/")
async def hello(request):
    return json({"message": "Hello, Sanic!"})

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

5. 扩展功能的解释

  • 记录请求执行时间:我们使用一个 defaultdict(list) 来记录每个 URL 请求的执行时间。在每次请求完成后,我们将执行时间添加到对应 URL 的列表中。
  • 统计平均执行时间:我们创建了一个 /stats 路由,用于返回每个路由的平均执行时间。

6. 总结

  • 使用 Sanic 中的 中间件 来统计请求的执行时间是非常简便的。通过记录请求开始和结束的时间,可以轻松计算出请求的执行时间。
  • 你可以根据自己的需求扩展这个功能,如统计最慢的请求、记录日志等。

这种方法能够帮助你监控应用的性能,尤其是在高并发的情况下,快速识别出潜在的性能瓶颈。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

pikachu靶场搭建详细步骤

一、靶场下载 点我去下载 二、靶场安装 需要的环境&#xff1a; mysqlApaches&#xff08;直接使用小皮面板Phpstudy&#xff1a;https://www.xp.cn/&#xff09;&#xff0c;启动他们 设置网站&#xff0c;把靶场的路径对应过来 对应数据库的信息 由于没有核对数据库的信…

Goland 安装与使用

GoLand安装 官方网址&#xff1a; JetBrains GoLand&#xff1a;不只是 Go IDE 1. 进入官网&#xff0c;点击下载&#xff1a; ​ 2. 如下图一步步安装 ​ ​ ​ ​ ​ 3. 如下图一步步安装

计算属性 简写和 完整写法

计算属性渲染不加上括号 methods方法和computed属性区别&#xff1a; computed只计算一次&#xff0c;然后缓存&#xff0c;后续直接拿出来使用&#xff0c;而methods每次使用每次计算&#xff0c;不会缓存 计算属性完整写法&#xff1a; 既获取又设置 slice 截取 成绩案例 …

2024最新鸿蒙开发面试题合集(二)-HarmonyOS NEXT Release(API 12 Release)

上一篇面试题链接&#xff1a;https://mp.csdn.net/mp_blog/creation/editor/144685078 1. 鸿蒙简单介绍和发展历程 HarmonyOS 是新一代的智能终端操作系统&#xff0c;为不同设备的智能化、互联与协同提供了统一的语言。带来简洁&#xff0c;流畅&#xff0c;连续&#xff0…

【C++】——精细化哈希表架构:理论与实践的综合分析

先找出你的能力在哪里&#xff0c;然后再决定你是谁。 —— 塔拉韦斯特弗 《你当像鸟飞往你的山》 目录 1. C 与哈希表&#xff1a;核心概念与引入 2. 哈希表的底层机制&#xff1a;原理与挑战 2.1 核心功能解析&#xff1a;效率与灵活性的平衡 2.2 哈希冲突的本质&#x…

修改 ssh 默认访问端口

Linux 最小化安装后默认带有 ssh 服务并正常运行&#xff0c;服务默认端口为“22”。为了确保访问网络的安全&#xff0c;很多用户的网络设备对“22”端口做了限制&#xff0c;这时我们需要修改 ssh 服务默认的端口。 此步骤建议直接在服务器上通过鼠标键盘操作 修改配置文件 …

HCIA-Access V2.5_6_3_GPON组网保护

Type B单归属保护 在PON网络中&#xff0c;从OLT到ONU,整个链路上只有一根光纤&#xff0c;如果光纤出现断裂&#xff0c;业务就会中断&#xff0c;如果断的是分支链路一般主要影响个别用户&#xff0c;一旦主干光纤出现问题&#xff0c;PON口下所有的用户都会造成中断&#xf…

Mybatis-Plus中的Page方法出现Records的值大于0但是total的值一直是0

最近在学习mybatis-plus的时候&#xff0c;做分页查询&#xff0c;出现了一个诡异的情况&#xff0c;就是 Records的值大于0但是total的值一直是0&#xff0c;经过一顿百度之后发现&#xff0c;是缺少了一个分页的bean 加上这个配置类就好了&#xff0c;网上说这是个分页的插件…

Docker 安装mysql ,redis,nacos

一、Mysql 一、Docker安装Mysql 1、启动Docker 启动&#xff1a;sudo systemctl start dockerservice docker start 停止&#xff1a;systemctl stop docker 重启&#xff1a;systemctl restart docker 2、查询mysql docker search mysql 3、安装mysql 3.1.默认拉取最新版…

从 Coding (Jenkinsfile) 到 Docker:全流程自动化部署 Spring Boot 实战指南(简化篇)

前言 本文记录使用 Coding (以 Jenkinsfile 为核心) 和 Docker 部署 Springboot 项目的过程&#xff0c;分享设置细节和一些注意问题。 1. 配置服务器环境 在实施此过程前&#xff0c;确保服务器已配置好 Docker、MySQL 和 Redis&#xff0c;可参考下列链接进行操作&#xff1…

python脚本:批量提取excel数据

这是一个脚本&#xff0c;用于提取文件夹下所有excel文件中的特定数据&#xff0c;并保存到一个新的excel文件。由于我的数据不多&#xff0c;就没有使用多线程。 要提取的数据如图中的检测项目 代码 import os import openpyxl## 第一步提取文件夹中的所有excle文件 # 1 设置…

绝美的数据处理图-三坐标轴-散点图-堆叠图-数据可视化图

clc clear close all %% 读取数据 load(MyColor.mat) %读取颜色包for iloop 1:25 %提取工作表数据data0(iloop) {readtable(data.xlsx,sheet,iloop)}; end%% 解析数据 countzeros(23,14); for iloop 1:25index(iloop) { cell2mat(table2array(data0{1,iloop}(1,1)))};data(i…

设计模式的主要分类是什么?请简要介绍每个分类的特点。

大家好&#xff0c;我是锋哥。今天分享关于【设计模式的主要分类是什么&#xff1f;请简要介绍每个分类的特点。】面试题。希望对大家有帮助&#xff1b; 设计模式的主要分类是什么&#xff1f;请简要介绍每个分类的特点。 1000道 互联网大厂Java工程师 精选面试题-Java资源分…

V-Ray 来到 Blender:为艺术家提供专业级渲染

Chaos 正式宣布将其行业领先的渲染引擎 V-Ray 集成到 Blender 中。这一备受期待的开发为 Blender 用户带来了专业级渲染功能&#xff0c;使他们能够直接在他们最喜欢的 3D 平台中制作令人惊叹的、逼真的图像和动画。 渲染 强大的可缩放渲染 使用 V-Ray 将您的渲染提升到一个…

三层交换原理及图示

大概 三层交换原理 需要提前掌握的&#xff08;VLAN基础知识&#xff09; 【Info-Finder 参考链接&#xff1a;什么是VLAN】 三层是IP层&#xff0c;即网络层。为了方便记忆的&#xff1a;“先有网络&#xff0c;才有传输”、“传输是为了验证有网络”、“IP不是Transfer”…

讯飞星火智能生成PPTAPi接口说明文档 python示例demo

接口调用流程图 常见问题&#xff1a;1、新版和旧版相比有什么变化&#xff1f; 新版提供了100主题模板&#xff0c;并且联网搜索、ai配图等功能2、新版的模板全部免费吗&#xff1f; 新版的100主题模板全部免费使用&#xff0c;不再额外扣量3、新版和旧版的接口可以混用吗&am…

win系统B站播放8k视频启用HEVC编码

下载HEVC插件 点击 HEVC Video Extension 2.2.20.0 latest downloads&#xff0c;根据教程下载安装 安装 Random User-Agent 点击 Random User-Agent 安装 配置 Random User-Agent ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/dda0ea75096c42c0a79ef6f6f5521…

JVM调优实践篇

理论篇 1多功能养鱼塘&#xff0d;JVM内存 大鱼塘O&#xff08;可分配内存&#xff09;&#xff1a; JVM可以调度使用的总的内存数&#xff0c;这个数量受操作系统进程寻址范围、系统虚拟内存总数、系统物理内存总数、其他系统运行所占用的内存资源等因素的制约。 小池塘A&a…

OSI 七层模型 | TCP/IP 四层模型

注&#xff1a;本文为 “OSI 七层模型 | TCP/IP 四层模型” 相关文章合辑。 未整理去重。 OSI 参考模型&#xff08;七层模型&#xff09; BeretSEC 于 2020-04-02 15:54:37 发布 OSI 的概念 七层模型&#xff0c;亦称 OSI&#xff08;Open System Interconnection&#xf…

Microsoft 365 Copilot模型多元化,降低对OpenAI依赖并降低成本

最近微软的新闻比较多&#xff0c;其中最令人瞩目的一条是&#xff0c;GitHub的copilot免费开放了&#xff0c;虽然次数较少&#xff08;代码补全每月2000次&#xff0c;chat对话每月50次&#xff09;&#xff0c;但至少是一个标志性事件&#xff0c;并且模型也由原来的单一的G…