FastAPI系列教程10:自定义FastAPI middleware中间件

本文介绍了FastAPI middleware中间件,可用于身份验证、日志记录等通用功能。阐述了其执行逻辑,工作于Request和Response之间。还介绍了三种创建中间件的方法,包括使用装饰器、继承BaseHTTPMiddleware和根据ASGI规范创建,利用中间件可让程序更强大、优雅可读。


在一些情况下,我们需要对整个FastAPI应用的全部或部分路由执行一些通用的功能,例如身份验证、日志记录、错误处理等,我们可以通过自定义FastAPI middleware中间件来完成。在FastAPI中也自带了一些常用的中间件来完成请求协议限定、跨域提交等。

一般情况下,碰到以下需求场景时,可以考虑使用FastAPI middleware来实现:
1、身份验证:验证请求的身份,例如检查 JWT token 或使用 OAuth2 进行验证。
2、日志记录:记录请求和响应的日志,包括请求方法、URL、响应状态码等信息。
3、错误处理:处理应用程序中的异常情况,例如捕获异常并返回自定义的错误响应。
4、请求处理:对请求进行处理,例如解析请求参数、验证请求数据等。
5、缓存:可以使用中间件来实现缓存功能,例如在中间件中检查缓存中是否存在请求的响应,如果存在则直接返回缓存的响应。

FastAPI middleware中间件执行逻辑

FastAPI middleware中间件工作在每一次的Request请求和Response响应之间,可以对Request和Response进行修改,其详细过程如下:
1、接收来自客户端的Request请求;
2、针对该次Request请求,自定义操作;
3、然后将Request请求传回原路由,由路由中定义的业务逻辑继续处理该次Request请求;
4、原路由业务处理完毕后,FastAPI middleware中间件将获得该路由产生的Response响应结果,此时可以针对Response响应结果自定义操作;
5、最后将Response响应结果发送给客户端;

创建FastAPI middleware中间件

使用装饰器创建中间件

在FastAPI应用中可以使用app.middleware(“http”)装饰器创建FastAPI middleware中间件。在以下例子中,我们在程序进入middleware时记录一对开始结束时间作为middleware时间,在程序进入路由业务逻辑中记录一对开始结束时间作为router时间,其中router开始时间为获取middleware写入request的middleware时间基础上加1小时,详细代码如下:

main.py

import time
from datetime import datetime, timedelta

import uvicorn as uvicorn
from fastapi import FastAPI
from starlette.requests import Request
from starlette.responses import Response

app = FastAPI()

# 将时间格式化为字符串
def _time2str(time_str):
    return datetime.strftime(time_str, '%Y-%m-%d %H:%M:%S')

# 将字符串转换为时间
def _str2time(time_str):
    return datetime.strptime(time_str, '%Y-%m-%d %H:%M:%S')

# 定义中间件
@app.middleware("http")
async def process_time_middleware(request: Request, call_next):
    # 接收来自客户端的Request请求;
    headers = dict(request.scope['headers'])
    # 定义middleware开始时间
    middleware_start_time = _time2str(datetime.now())
    # 将middleware开始时间添加到request的headers中,这里request.headers是一个可读可写的对象,但是它的值是不可变的,所以这里需要将request.headers转换为字典,然后再修改字典的值,最后再将字典转换为元组,赋值给request.scope['headers'];
    headers[b'middleware_start_time'] = middleware_start_time.encode('utf-8')
    request.scope['headers'] = [(k, v) for k, v in headers.items()]

    # 将Request请求传回原路由
    response = await call_next(request)

    # 为了更好的观察middleware的执行过程,这里让middleware休眠1秒钟
    time.sleep(1)

    # 接收来自原路由的Response响应,将middleware结束时间添加到response的headers中
    response.headers["middleware_start_time"] = middleware_start_time
    response.headers["middleware_end_time"] = _time2str(datetime.now())

    return response


@app.get("/")
async def index(request: Request, response: Response
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值