首页 > 其他分享 >FastAPI系列:中间件

FastAPI系列:中间件

时间:2024-02-28 18:00:28浏览次数:23  
标签:__ 系列 FastAPI app 中间件 scope self def

中间件介绍

中间件是一个函数,它在每个请求被特定的路径操作处理之前 ,以及在每个响应返回之前工作

装饰器版中间件

1.必须使用装饰器@app.middleware("http"),且middleware_type必须为http
2.中间件参数:request, call_next,且call_next 它将接收 request 作为参数

@app.middleware("http")
async def custom_middleware(request: Request, call_next):
    logger.info("Before request")
    response = await call_next(request)  # 让请求继续处理
    logger.info("After request")
    # 也可以在返回response之前做一些事情,比如添加响应头header
    # response.headers['xxx'] = 'xxx'
    return response


@app.get("/")
def read_root():
    logger.info("执行了.......")
    return {"message": "hello world"}

自定义中间件BaseHTTPMiddleware

BaseHTTPMiddleware是一个抽象类,允许您针对请求/响应接口编写ASGI中间件

要使用 实现中间件类BaseHTTPMiddleware,您必须重写该 async def dispatch(request, call_next)方法,

如果您想为中间件类提供配置选项,您应该重写该__init__方法,确保第一个参数是app,并且任何剩余参数都是可选关键字参数。app 如果执行此操作,请确保在实例上设置该属性。

# 通过继承BaseHTTPMiddleware来实现自定义的中间件
import time

from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint
from fastapi import FastAPI, Request
from starlette.responses import Response

app = FastAPI()

# 基于BaseHTTPMiddleware的中间件实例
class TimeCcalculateMiddleware(BaseHTTPMiddleware):
    # dispatch必须实现
    async def dispatch(self, request: Request, call_next):
        print('start')
        start_time = time.time()
        response = await call_next(request)
        process_time = round(time.time() - start_time, 4)
        #返回接口响应事件
        response.headers['X-Process-Time'] = f"{process_time} (s)"
        print('end')
        return response


class AuthMiddleware(BaseHTTPMiddleware):
    def __init__(self,app, header_value='auth'):
        super().__init__(app)
        self.header_value = header_value
        
    #dispatch必须实现 
    async def dispatch(self, request:Request, call_next):
        print('auth start')
        response =  await call_next(request)
        response.headers['Custom'] = self.header_value
        print('auth end')
        return response
        
# fastapi实例的add_middleware方法
app.add_middleware(TimeCcalculateMiddleware)
app.add_middleware(AuthMiddleware, header_value='CustomAuth')

@app.get('/index')
async def index():
    print('index start')
    return  {
        'code': 200
    }

"""执行顺序
auth start
start
index start
end
auth end
"""

ip白名单中间件(基于纯ASGI中间)

根据官网说明BaseHTTPMiddleware有一些已知的局限性:

使用BaseHTTPMiddleware将阻止对contextlib.ContextVar的更改向上传播。
也就是说,如果您ContextVar在端点中设置 a 值并尝试从中间件读取它,您会发现该值与您在端点中设置的值不同

纯ASGI中间件,使用类的方式

class ASGIMiddleware:
    def __init__(self, app):
        self.app = app

    async def __call__(self, scope, receive, send):
        await self.app(scope, receive, send)

上面的中间件是最基本的ASGI中间件。它接收父 ASGI 应用程序作为其构造函数的参数,并实现async __call__调用该父应用程序的方法。
无论如何,ASGI 中间件必须是接受三个参数的可调用对象:scopereceivesend

  • scope是一个保存有关连接信息的字典,其中scope["type"]可能是:
  • receivesend 可以用来与ASGI服务器交换ASGI事件消息。这些消息的类型和内容取决于作用域类型。在ASGI规范中了解更多信息
# 基于自定义类来实现
from fastapi import FastAPI
app = FastAPI()

from starlette.responses import PlainTextResponse
from starlette.types import ASGIApp, Receive, Scope, Send
from starlette.requests import HTTPConnection
import typing

class WhiteIpMiddleware:
    def __init(self, app:ASGIApp, allow_ip: typing.Sequence[str] = ()) -> None:
        self.app = app
        self.allow_ip = allow_ip or '*'
        
    async def __call__(self, scope:Scope, receive:Receive, send:Send)->None:
        if scope['type'] in ('http','websocket') and scope['scheme'] in ('http', 'ws'):
            conn = HTTPConnection(scope=scope)
            if self.allow_ip and conn.client.host not in self.allow_ip:
                response = PlainTextResponse(content='不在ip白名单内', status_code=403)
                await response(scope, receive, send)
                return
            await self.app(scope, receive, send)
        else:
            await self.app(scope, receive, send)

app.add_middleware(WhiteIpMiddleware, allow_ip=['127.0.0.2'])

@app.get('/index')
async def index():
    print('index-start')
    return {'code': 200}

跨域中间件cors

同源:协议,域,端口相同

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware  # fastapi内置了一个CORSMiddleware,可以直接使用
import uvicorn
app = FastAPI()

origins = [
    "http://localhost.tiangolo.com",
    "https://localhost.tiangolo.com",
    "http://localhost",
    "http://localhost:8080",
]

app.add_middleware(
	CORSMiddleware,
    allow_origins=origins,  #一个允许跨域请求的源列表
    allow_credentials=True, #指示跨域请求支持 cookies,默认False, 另外,允许凭证时allow_origins 不能设定为 ['*'],必须指定源。
    allow_methods=["*"], # 一个允许跨域请求的 HTTP 方法列表,默认get
    allow_headers=["*"], # 一个允许跨域请求的 HTTP 请求头列表
)

@app.get("/")
async def main():
    return {"message": "hello world"}

if __name__ == '__main__':
    uvicorn.run(app=app)

标签:__,系列,FastAPI,app,中间件,scope,self,def
From: https://www.cnblogs.com/weiweivip666/p/18041311

相关文章

  • FastAPI系列:模型用法
    模型基本用法frompydanticimportBaseModelclassItem(BaseModel):#通过继承BaseModelname:strprice:floatis_offer:Union[bool,None]=None常用的模型属性和方法dict()#将数据模型的字段和值封装成字典json()#将数据模型的字段和值封装成json格......
  • FastAPI系列:上传文件File和UploadFile
    上传文件#file仅适用于小文件@app.post("/files/")asyncdefcreate_file(file:bytes|None=File(default=None)):ifnotfile:return{"message":"Nofilesent"}else:return{"file_size":len(file)}......
  • FastAPI系列:路径参数额外校验Path
    路径参数额外校验PathfromfastapiimportPathapp=FastAPI()@app.get('/items/{item_id}')asyncdefread_items(item_id:str=Path(default=None,max_length=3,min_length=1,title='theidofitemtoget')):"""def......
  • FastAPI系列:查询字符串参数
    单个查询字符串@app.get('/index/{username}')defindex(username:str,id:int):#id为查询字符串?id=5return{"message":"success","username":username,"id":id}可选的查询字符串参数@app.get('/items/{item_id}......
  • FastAPI系列:APIRouter实例的路由注册
    APIRouter实例的路由注册API端点路由注册大致分为3种:1.基于app实例对象提供的装饰器或函数进行注册2.基于FastAPI提供的APIRouter类的实例对象提供的装饰器或函数进行注册3.通过直接实例化APIRoute对象且添加的方式进行注册路由注册方式基于APIRouter的实例对象实现路由注册......
  • FastAPI系列:mount应用挂载
    mount应用挂载1.创建主app应用对象实例,注册所属的路由信息fromfastapiimportFastAPIfromfastapi.responseimportJSONResponseapp=FastAPI(title='主应用',description='主应用描述',version='v1.0.0')@app.get('/index',summary='首页')......
  • FastAPI系列:全局routes参数的使用
    全局routes参数的使用fromfastapiimportFastAPI,Requestfromfastapi.responseimportJSONResponsefromfastapi.routingimportAPIRouteasyncdeffastapi_index():returnJSONResponse({'index':'fastapi_index'})asyncdeffastapi_about()......
  • FastAPI系列:路由之节点元数据参数说明
    节点元数据参数说明#拿app.get()方法的参数来说明,其他的差不多类似defget(self,path:str,*,response_model:Optional[Type[Any]]=None,status_code:Optional[int]=None,tags:Optional[List[Union[str,Enum]]]......
  • FastAPI系列:路由之APIRouter参数介绍
    APIRouter参数介绍classAPIRouter(routing.Router):def__init__(self,*,prefix:str="",#表示当前路由分组的url前缀tags:Optional[List[Union[str,Enum]]]=None,#表示当前路由分组在可交互文档中所属的分组标签列表。一......
  • FastAPI系列 :安装启动及简单示例
    安装pip3installfastapipip3installuvicorn[standard]#是一个ASGI异步服务器网关接口服务器框架pip3installpython-multipart#处理表单参数的#完整安装pipinstallfastapi[all]启动程序#命令行启动uvicornmain:app--reload--host0.0.0.0--port8888......