FastAPI中间件包装响应报错,如何正确将原结果作为字典元素返回?
问题
用户编写了如下FastAPI代码,试图通过HTTP中间件将接口的原响应结果作为字典的response元素返回:
from fastapi import FastAPI, Request from fastapi.responses import JSONResponse app = FastAPI() @app.middleware("http") async def response_middleware(request: Request, call_next): # 执行请求 results = await call_next(request) return JSONResponse(content={ 'response': results }) @app.post("/test/") async def test_func(): results = { 'test': 10 } return results
运行时触发错误:
raise TypeError(f'Object of type {o.__class__.__name__} ' TypeError: Object of type _StreamingResponse is not JSON serializable
用户尝试直接返回字典,问题仍未解决:
async def response_middleware(request: Request, call_next): # 执行请求 results = await call_next(request) return { 'response': results }
现需解决两个问题:
- 如何正确将原结果作为输出字典元素传递?
- 是否必须使用JSONResponse?
解答
错误原因
call_next(request)返回的是响应对象(比如JSONResponse或内部的_StreamingResponse),而非直接的响应内容(字典/JSON数据)。直接把这个对象放进JSONResponse的content里,会因响应对象无法被JSON序列化而报错。
正确实现方式
方法1:读取原响应内容重新封装
先获取原响应的状态码、请求头,再读取并解析响应体内容,最后将其封装到目标字典中返回:
from fastapi import FastAPI, Request from fastapi.responses import JSONResponse import json app = FastAPI() @app.middleware("http") async def response_middleware(request: Request, call_next): response = await call_next(request) # 读取原响应体的二进制内容并解析为字典 body = await response.body() original_content = json.loads(body) # 封装成统一格式的响应,保留原响应的状态码和请求头 return JSONResponse( content={'response': original_content}, status_code=response.status_code, headers=dict(response.headers) ) @app.post("/test/") async def test_func(): return {'test': 10}
注意:该方法仅适用于原响应为JSON格式的接口,若原响应是HTML、二进制文件等格式,需针对性调整解析逻辑。
方法2:用响应模型替代中间件(更简洁)
如果所有接口都需要统一响应格式,推荐使用FastAPI的响应模型功能,无需中间件:
from fastapi import FastAPI from pydantic import BaseModel app = FastAPI() # 定义统一的响应模型 class UnifiedResponse(BaseModel): response: dict @app.post("/test/", response_model=UnifiedResponse) async def test_func(): # 直接返回符合模型结构的数据 return {'response': {'test': 10}}
是否必须使用JSONResponse?
不是必须,但要明确以下几点:
- 若接口统一返回JSON格式,使用
JSONResponse是最规范的做法,FastAPI也会自动将字典转换为JSONResponse。 - 在中间件中,必须返回响应对象(如
JSONResponse、HTMLResponse等),不能直接返回字典——虽然FastAPI会自动将字典转为JSONResponse,但这里你要包裹的是原响应内容,直接返回字典会因原响应对象无法序列化而报错,逻辑也不符合预期。
内容的提问来源于stack exchange,提问作者Zhihar
相关产品推荐
相关产品推荐

