[Python3] Sanic中间件

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

在这里插入图片描述

Sanic 中间件的工作流程

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

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

中间件的使用

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

1. 全局中间件

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

请求阶段的全局中间件

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

from sanic import Sanic
from sanic.response import jsonapp = 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 timeapp = 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 defaultdictapp = 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_timeprint(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 中的 中间件 来统计请求的执行时间是非常简便的。通过记录请求开始和结束的时间,可以轻松计算出请求的执行时间。
  • 你可以根据自己的需求扩展这个功能,如统计最慢的请求、记录日志等。

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

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

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

相关文章

使用 OpenCV 绘制线条和矩形

OpenCV 是一个功能强大的计算机视觉库&#xff0c;它不仅提供了丰富的图像处理功能&#xff0c;还支持图像的绘制。绘制简单的几何图形&#xff08;如线条和矩形&#xff09;是 OpenCV 中常见的操作。在本篇文章中&#xff0c;我们将介绍如何使用 OpenCV 在图像上绘制线条和矩形…

操作系统课程设计

摘 要 本项目旨在深入设计与实现一套基于Java的模拟操作系统&#xff0c;模拟和实现常见操作系统的核心功能&#xff0c;包括进程管理、内存分配与调度、高效的文件系统和多样化设备的管理。通过该模拟操作系统的开发&#xff0c;探索计算机操作系统的基础理论与实际工程细节…

css改变输入右下角图标

前言 正常情况下&#xff0c;HTML textarea 多行文本输入框会存如下图所示图标&#xff0c; 用户可拉动它改变高度&#xff0c;这是我们不想看到的&#xff0c;所以要去掉它。 去掉后&#xff1a; 解决方案 设置 resize 属性即可&#xff0c;如下代码所示&#xff1a; <…

HTML-CSS(day01)

W3C标准&#xff1a; W3C&#xff08; World Wide Web Consortium&#xff0c;万维网联盟&#xff09; W3C是万维网联盟&#xff0c;这个组成是用来定义标准的。他们规定了一个网页是由三部分组成&#xff0c;分别是&#xff1a; 三个组成部分&#xff1a;&#xff08;1&…

2024-12-24 NO1. XR Interaction ToolKit 环境配置

文章目录 1 软件配置2 安装 XRToolKit3 配置 OpenXR4 安装示例场景5 运行测试 1 软件配置 Unity 版本&#xff1a;Unity6000.0.26 ​ 2 安装 XRToolKit 创建新项目&#xff08;URP 3D&#xff09;&#xff0c;点击进入 Asset Store。 进入“Unity Registry”页签&#xff0…

C语言基础——指针(4)

一&#xff0e; 字符指针变量 字符指针变量的使用和整型指针变量的使用方法相似&#xff0c;以下是其基本使用方法的例子&#xff1a; &#xff08;1&#xff09;字符指针变量还有一种使用方法&#xff1a; const char* p "abcd" 需…

week 11 - BCNF

1. More on functional dependencies (功能依赖的更多内容) Lossless decomposition (无损分解) 研究如何在分解表的过程中不丢失信息&#xff0c;也就是说&#xff0c;通过分解后的表可以无损地重建原始表。 2. BCNF (Boyce-Codd Normal Form, BCNF范式) &#xff08;1&…

嵌入式学习-QT-Day06

嵌入式学习-QT-Day06 六、多窗口编程 1、QMessageBox 消息对话框 2、QWidget类 3、parent参数 4、堆栈窗口&#xff08;QStackedWidget&#xff09; 5、新建自定义窗口类 6、对象传值 6.1 父对象 → 子对象 6.2 子对象 → 父对象 7、事件机制 8、QMainWindow主窗口类 8.1 QMenu…

《战神:诸神黄昏》游戏运行时提示找不到gamede.dll文件怎么办?gamede.dll丢失的修复指南

在沉浸于《战神&#xff1a;诸神黄昏》的壮阔世界时&#xff0c;突然弹出的“找不到gamede.dll文件”错误提示可能会让玩家措手不及。作为一名经验丰富的软件开发从业者&#xff0c;我深知这类问题对游戏体验的影响。今天&#xff0c;我将为大家详细解析gamede.dll文件丢失的原…

1.系统学习-线性回归

系统学习-线性回归 前言线性回归介绍误差函数梯度下降梯度下降示例 回归问题常见的评价函数1. MAE, mean absolutely error2. MSE, mean squared error3. R square &#xff08;决定系数或R方&#xff09; 机器学习建模流程模型正则化拓展阅读作业 链接: 2.系统学习-逻辑回归 …

基于微信小程序的校园访客登记系统

基于微信小程序的校园访客登记系统 功能列表 用户端功能 注册与登录 &#xff1a;支持用户通过手机号短信验证码注册和登录。个人资料管理 &#xff1a;允许用户编辑和更新个人信息及其密码。站内信消息通知&#xff1a;通知公告。来访预约&#xff1a;提交来访预约支持车牌…

H3C MPLS跨域optionB

实验拓扑 实验需求 如图,VPN1 和 VPN2 分别通过运营商 MPLS VPN 连接各自分支机构按照图示配置 IP 地址,VPN1 和 VPN2 连接同一个 PE 设备的私网 IP 网段存在地址复用,使用多 VRF 技术来防止 IP 冲突AS 100 和 AS 200 内部的公共网络中各自运行 OSPF 使 AS 内各设备的 Loo…

【项目管理】根据业务流程进行函数结构设计和模块化设计

在开发一个复杂的系统时&#xff0c;根据业务流程进行函数结构设计和模块化设计是一个非常重要的步骤。通过这种方式&#xff0c;能够将复杂的业务逻辑拆分成多个功能模块和函数&#xff0c;使代码更清晰、易维护、易扩展。我们在写代码的时候需要基于对于业务的理解来编程&…

VMware虚拟机中CentOS系统/dev/mapper/centos-home分区扩容指南

要将VMware上新扩展的磁盘添加到CentOS虚拟机,并将其扩容到/dev/mapper/centos-home下,你可以按照以下步骤操作: 一、在VMware中扩展虚拟机磁盘 关闭CentOS虚拟机:确保在扩展磁盘之前,CentOS虚拟机已经关闭。 编辑虚拟机设置:在VMware中,右键点击CentOS虚拟机,选择“设…

GPUStack v0.4.1 单节点与多节点安装与部署指南 Docker PowerShell

Introduce GPUStack 是一个开源的 GPU 集群管理器&#xff0c;专为运行 AI 模型而设计。它以其广泛的硬件兼容性而闻名&#xff0c;支持多种品牌的 GPU&#xff0c;并能在 Apple MacBook、Windows PC 和 Linux 服务器上运行。 GPUStack支持各种AI模型&#xff0c;包括大型语言…

【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析

Hiヽ(゜▽゜ )&#xff0d;欢迎来到蓝染Aizen的CSDN博客~ &#x1f525; 博客主页&#xff1a; 【✨蓝染 の Blog&#x1f618;】 &#x1f496;感谢大家点赞&#x1f44d; 收藏⭐ 评论✍ 文章目录 行为型模式1、模板方法模式&#xff08;1&#xff09;概述&#xff08;2&…

【解决报错】AttributeError: ‘NoneType‘ object has no attribute ‘group‘

学习爬虫时&#xff0c;遇到如下报错&#xff1a; 报错原因&#xff1a; 正则表达式的 search 或 finditer 方法没有找到任何匹配项&#xff0c;可能是换行符处理不当等。 解决方法如下&#xff1a; 在正则表达式末尾加上re.S即可&#xff0c;re.S是一个编译标志&#xff0c…

一款5k star的 Redis 客户端!!简洁高效!

作为一名热爱编程的程序员&#xff0c;对于高效的工具总是格外追求。在日常的开发中&#xff0c;Redis 作为一款优秀的内存数据库&#xff0c;是我们不可或缺的利器之一。了不起之前也推荐过一些出色的 Redis 客户端&#xff0c;它们在提升我们的开发效率和便利性方面发挥了巨大…

关于科研中使用linux服务器的集锦

文章目录 常用的linux命令下载COCO2017数据集 常用的linux命令 一个文件移动到另一个目录下的命令是&#xff1a;mv -v ./old_name ./new_name 如果目标文件夹中已经有同名文件或文件夹&#xff0c;mv 会覆盖它们&#xff08;除非使用了 -i 选项来提示确认&#xff09;。 使用…

Vue开发环境搭建上篇:安装NVM和NPM(cpnm、pnpm)

文章目录 引言I 安装NVM1.1 Windows系统安装NVM,实现Node.js多版本管理1.2 配置下载镜像1.3 NVM常用操作命令II NPM永久使用淘宝源安装 cnpm安装pnpm【推荐】see also: vscode常用插件引言 淘宝镜像:http://npm.taobao.org 和 http://registry.npm.taobao.org 已在 2022.06.3…