FastAPI自定义中间件调用await request.form()后无响应(连接超时)
FastAPI中间件调用
request.form()后超时的问题解决 问题根源
在中间件中调用await request.form()会直接消耗请求体的数据流。FastAPI底层的Starlette框架中,请求体是流式且不可重复读取的。当后续call_next(request)把请求传递给业务路由时,路由尝试读取请求体时会发现没有数据,一直处于等待状态,最终导致连接超时。
解决办法
方法1:缓存请求体,允许重复读取
先读取请求体并缓存,再重新构建请求对象,确保下游路由能正常读取请求体:
from fastapi import Request from starlette.middleware.base import BaseHTTPMiddleware class AuthMiddleWare(BaseHTTPMiddleware): def __init__(self, app, some_attribute: str): super().__init__(app) self.some_attribute = some_attribute async def dispatch(self, request: Request, call_next): # 缓存原始请求体 body = await request.body() # 替换请求内部的body缓存,让后续读取有效 request._body = body await self.before_request(request) response = await call_next(request) self.after_request(request) print('call next executes') return response async def before_request(self, request: Request): try: print('------------------ before request starts ----------------') print(request.url) print(request.method) print(request.client.host) print(request.client.port) print(request.base_url) # 此时读取form不会消耗请求体 form = await request.form() firstname = form.get('firstname') print(firstname) print('------------------ before request ends ----------------') except Exception as e: print(f'发生异常: {str(e)}') def after_request(self, request: Request): pass
方法2:将form数据存入request.state,下游直接复用
如果中间件读取form后,下游路由不需要再处理原始请求体,可将解析后的form数据存入request.state,下游直接取用即可:
from fastapi import Request from starlette.middleware.base import BaseHTTPMiddleware class AuthMiddleWare(BaseHTTPMiddleware): def __init__(self, app, some_attribute: str): super().__init__(app) self.some_attribute = some_attribute async def dispatch(self, request: Request, call_next): await self.before_request(request) response = await call_next(request) self.after_request(request) print('call next executes') return response async def before_request(self, request: Request): try: print('------------------ before request starts ----------------') print(request.url) print(request.method) print(request.client.host) print(request.client.port) print(request.base_url) form = await request.form() firstname = form.get('firstname') print(firstname) # 把form数据存入request.state,下游路由直接用 request.state.form_data = form print('------------------ before request ends ----------------') except Exception as e: print(f'发生异常: {str(e)}') request.state.form_data = None def after_request(self, request: Request): pass
下游路由示例:
from fastapi import FastAPI, Request app = FastAPI() app.add_middleware(AuthMiddleWare, some_attribute="test") @app.post("/test") async def test(request: Request): return {"firstname": request.state.form_data.get("firstname") if request.state.form_data else None}
内容的提问来源于stack exchange,提问作者M. Mudassar
相关产品推荐
相关产品推荐

