ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

FastAPI `Response` 类参考:参数注入与直接返回的完整解析

FastAPI `Response` 类参考:参数注入与直接返回的完整解析 FastAPIResponse类参考参数注入与直接返回的完整解析【免费下载链接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production项目地址: https://gitcode.com/GitHub_Trending/fa/fastapiResponse是 FastAPI 提供的核心响应基类也是整个响应体系的根基你既可以把Response类型声明为路径操作函数或依赖的参数在请求处理过程中动态修改响应头、Cookie 和状态码也可以直接创建并返回Response或其子类实例完全绕过 FastAPI 的数据序列化流程。读完本文你将掌握Response的两种官方用法、其在 FastAPI 源码中的注入与直通机制fastapi/dependencies/utils.py、fastapi/routing.py中的关键调用链以及直接返回Response与使用 Response Model 之间的性能取舍。1.Response是什么来自 Starlette 的响应基类FastAPI 本身不定义Response的实现而是从 Starlette 直接再导出。在 fastapi/responses.py 中可以看到from starlette.responses import FileResponse as FileResponse # noqa from starlette.responses import HTMLResponse as HTMLResponse # noqa from starlette.responses import JSONResponse as JSONResponse # noqa from starlette.responses import PlainTextResponse as PlainTextResponse # noqa from starlette.responses import RedirectResponse as RedirectResponse # noqa from starlette.responses import Response as Response # noqa from starlette.responses import StreamingResponse as StreamingResponse # noqa官方参考文档给出的导入方式就是从fastapi直接导入from fastapi import Response从源码结构看fastapi.responses与fastapi.Response只是对 Starlette 同名类的便捷再导出FastAPI 文档在 返回 Response 指南 中也明确说明“FastAPI 提供的starlette.responses就是fastapi.responses只是方便开发者”因此Response的构造参数遵循 Starlette 的约定参数说明content响应体通常为bytes如b直接返回时由你自行负责编码与格式status_codeHTTP 状态码默认为200可任意设置为合法值如201、204headers响应头dict形式media_type媒体类型如application/xml会写入Content-Typebackground后台任务对象响应发送完成后执行由于它是所有具体响应类JSONResponse、HTMLResponse等的基类FastAPI 用isinstance(x, Response)来判断一个路径操作的返回值是否为“直接返回的响应”。2. 用法一作为参数注入动态修改响应官方参考文档 Response class 的第一种用法是在路径操作函数或依赖中声明一个类型为Response的参数然后修改响应数据如 headers 或 cookies。from fastapi import Depends, FastAPI, Response app FastAPI() def set_cookie(response: Response) - None: response.set_cookie(keysession, valueabc123) def set_header(response: Response) - None: response.headers[X-Custom-Header] my-value app.get(/, dependencies[Depends(set_cookie), Depends(set_header)]) async def read(): return {msg: Hello World}依赖函数中设置的 Cookie 和响应头会随最终响应一起发出。这条链路的源码依据在 fastapi/dependencies/utils.py参数识别add_non_field_param_to_dependency()在分析函数签名时发现类型注解是Response的子类就记录参数名——elif lenient_issubclass(type_annotation, Response): dependant.response_param_name param_name return True实例创建solve_dependencies()在解析依赖树之前如果没有现成的响应对象会创建一个占位实例并先移除content-length头、把status_code置空此时响应体尚未确定长度未知保证所有层级的依赖共享同一个对象——if response is None: response Response() del response.headers[content-length] response.status_code None # type: ignore参数注入解析完成后把该实例按名字塞进调用参数——if dependant.response_param_name: values[dependant.response_param_name] response正因为依赖与路径操作拿到的是同一个Response实例依赖里改的头、状态码、Cookie 才能对最终响应生效。仓库测试 tests/test_response_change_status_code.py 正是这样验证的依赖response_status_setter中执行response.status_code 201最终TestClient收到的响应状态码即为201而响应体仍是路径操作返回的{msg: Hello World}。这些头部最终是在 fastapi/routing.py 中与真正要发送的响应合并的response.headers.raw.extend(solved_result.response.headers.raw)即依赖/路径操作里注入的那个Response对象上累积的所有原始头部都会被合并进最终响应的头部。3. 用法二直接返回Response实例参考文档的第二种用法是直接创建Response或其子类实例并从路径操作返回。from fastapi import FastAPI, Response app FastAPI() app.get(/legacy/) def get_legacy_data(): data ?xml version1.0? shampoo Header Apply shampoo here. /Header Body Youll have to use soap here. /Body /shampoo return Response(contentdata, media_typeapplication/xml)这个示例完整保留自仓库官方教程源码 docs_src/response_directly/tutorial002_py310.py把 XML 字符串放进Response指定media_typeapplication/xml后直接返回。路由层的处理逻辑在 fastapi/routing.py 的get_route_handler()生成的app()中路径操作调用结束后raw_response await run_endpoint_function( dependantdependant, valuessolved_result.values, is_coroutineis_coroutine, ) if isinstance(raw_response, Response): if raw_response.background is None: raw_response.background solved_result.background_tasks response raw_response这揭示了三个关键行为直通机制只要返回值是Response实例包括JSONResponse、HTMLResponse等所有子类FastAPI 原样把它作为最终响应不做任何 Pydantic 模型转换、不经过response_model校验也不做jsonable_encoder编码——这正是文档所说“带来很大灵活性也带来很大责任”后台任务接管如果返回的Response没有设置backgroundFastAPI 会把依赖层积累的BackgroundTasks挂到它上面保证依赖中注册的后台任务在直接返回Response时依然执行状态码约束对非直接返回的响应FastAPI 还会检查is_body_allowed_for_status_code(response.status_code)例如204、304这类不允许携带响应体的状态码会把response.body置为b。4. 直接返回JSONResponse配合jsonable_encoder当返回的是dict/Pydantic 模型而非Response实例时FastAPI 默认会用jsonable_encoder转成JSONResponse。如果你需要手动构造JSONResponse例如要控制状态码和头部同时返回 JSON先把不可 JSON 序列化的数据datetime、UUID等转好即可。以下示例来自 docs_src/response_directly/tutorial001_py310.pyfrom datetime import datetime from fastapi import FastAPI from fastapi.encoders import jsonable_encoder from fastapi.responses import JSONResponse from pydantic import BaseModel class Item(BaseModel): title: str timestamp: datetime description: str | None None app FastAPI() app.put(/items/{id}) def update_item(id: str, item: Item): json_compatible_item_data jsonable_encoder(item) return JSONResponse(contentjson_compatible_item_data)这里item包含datetime字段直接塞进JSONResponse会失败jsonable_encoder(item)先将其转换为 JSON 兼容的dict再由JSONResponse序列化。注意JSONResponse本身就是Response的子类因此它同样走上面第 3 节的“直通”分支。5. 取舍直接返回Responsevs. 声明 Response Model直接返回Response意味着数据不会被校验、不会被转换序列化、也不会自动写入 OpenAPI 文档OpenAPI 中仍可手动补充说明参考 Additional Responses in OpenAPI。因此需要权衡选 Response Model返回类型或response_model性能更好。从 fastapi/routing.py 的响应序列化分支可以看到当存在带TypeAdapter的响应字段且未设置自定义响应类时FastAPI 会走 Pydanticdump_json快速路径把数据直接序列化为 JSON 字节Rust 核心完成跳过“中间 Python dict json.dumps()”这一步然后用原生Response(content..., media_typeapplication/json)返回# Use the fast path (dump_json) when no custom response # class was set and a response field with a TypeAdapter # exists. Serializes directly to JSON bytes via Pydantics # Rust core, skipping the intermediate Python dict # json.dumps() step. use_dump_json response_field is not None and isinstance( response_class, DefaultPlaceholder ) ... if use_dump_json: response Response( contentcontent, media_typeapplication/json, **response_args, )这也解释了官方文档的提示通常使用 Response Model 的性能要高于直接返回JSONResponse。仓库测试 tests/test_dump_json_fast_path.py 专门覆盖了这条快速路径。选直接返回Response当你需要返回非 JSON 数据XML、纯文本、文件、流、需要自定义媒体类型、或要完全控制序列化格式时直接返回是最直接的方式。依赖注入式用法第 2 节与二者都不冲突无论最终响应是模型序列化产物还是直接返回的Response依赖中设置的响应头都会被response.headers.raw.extend(...)合并进最终响应。6. 同模块中可用的其他响应类fastapi/responses.py 除了Response外还再导出了一整套 Starlette 响应类导入方式与Response一致from fastapi.responses import JSONResponse, HTMLResponse, PlainTextResponse from fastapi.responses import RedirectResponse, StreamingResponse, FileResponse from fastapi.responses import EventSourceResponse另外需要留意的是同文件中的UJSONResponse与ORJSONResponse两个JSONResponse子类已被标记弃用带deprecated装饰器原因是“FastAPI 现在在设置了返回类型或 response model 时会通过 Pydantic 直接把数据序列化为 JSON 字节速度更快且无需自定义响应类”。因此在当前版本中若追求更快的 JSON 序列化应优先依赖 Response Model / 返回类型机制而不是引入已弃用的响应类。7. 小结与延伸阅读Response类参考的核心要点可以归纳为Response直接从starlette.responses再导出是 FastAPI 所有响应类的基类注入用法声明Response类型参数即可在路径操作或依赖中设置 headers、cookies、状态码底层依赖fastapi/dependencies/utils.py的参数识别与单实例共享机制直返用法返回Response实例时 FastAPI 原样透传、不校验不序列化但会自动接管后台任务并对不允许携带响应体的状态码清空 body优先用 Response Model 获得 Pydantic Rust 核心的直接序列化性能仅在需要控制传输细节时直接返回Response。进一步阅读均为仓库内相对路径参考文档原文docs/en/docs/reference/response.md直接返回响应教程docs/en/docs/advanced/response-directly.md教程源码示例docs_src/response_directly/tutorial001_py310.py、docs_src/response_directly/tutorial002_py310.py响应类定义与再导出fastapi/responses.py路由与直通逻辑fastapi/routing.py依赖注入逻辑fastapi/dependencies/utils.py相关测试tests/test_response_change_status_code.py、tests/test_response_dependency.py【免费下载链接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production项目地址: https://gitcode.com/GitHub_Trending/fa/fastapi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表