ARTICLE DETAIL

资讯详情

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

FastAPI 高级用法:在路径操作函数中直接使用 Request 对象

FastAPI 高级用法:在路径操作函数中直接使用 Request 对象 FastAPI 高级用法在路径操作函数中直接使用 Request 对象【免费下载链接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production项目地址: https://gitcode.com/GitHub_Trending/fa/fastapiFastAPI 的声明式参数路径参数、查询参数、请求头、Cookie、请求体等会自动完成数据校验、类型转换和 OpenAPI 文档生成。但在某些场景下——例如读取客户端真实 IP/主机名、直接访问原始请求头、或者需要完全自定义的数据读取逻辑——你需要绕过这套魔法直接操作底层的Request对象。本文将以仓库中 法语文档与英文原版内容一致为主体结合docs_src示例与fastapi/源码说明如何安全地混合使用声明式参数与原始Request对象并厘清两者在验证与文档生成上的差异。先理解声明式参数为你做了什么到目前为止你一直在按需要哪部分请求数据的方式声明参数并带上类型注解路径参数path parameters查询参数query parameters请求头headersCookie请求体body如 Pydantic 模型等等。通过这种方式FastAPI会自动完成三件事校验数据是否符合声明的类型与约束转换数据为指定类型为 API 自动生成文档OpenAPI并反映到/docs自动交互界面中。这套机制让绝大多数业务代码无需关心 HTTP 层细节。但正如文档指出的仍然存在需要直接访问Request对象的特定情况。Request对象的本质FastAPI 之下就是 Starlette关键背景是FastAPI 本质上构建在 Starlette 之上它只是在 Starlette 外面套了一层工具路由声明、依赖注入、数据校验、文档生成等。因此当你有需要时可以直接使用 Starlette 的Request对象。在仓库中可以看到这一点被显式地保留了下来fastapi/requests.py 只有两行再导出语句将 Starlette 的Request以及HTTPConnection原样再导出而 fastapi/init.py 又通过from .requests import Request as Request把Request暴露为fastapi.Request。换句话说下面的两种写法完全等价fastapi.Request只是 FastAPI 为了方便开发者提供的快捷入口其实现来自 Starlettefrom fastapi import Request # 等价于 from starlette.requests import Request直接读取 Request 的代价一个必须牢记的边界是如果你直接从Request对象上取数据例如读取原始请求体这些数据不会被 FastAPI 校验、转换也不会出现在 OpenAPI/自动接口文档中。反向来看其余按常规声明的参数例如用 Pydantic 模型声明的请求体依然会被校验、转换、标注到 OpenAPI 中。也就是说直接访问 Request与声明式参数不是互斥关系而是一种补充手段——只有在确实拿不到、或不好用声明式表达的信息如客户端地址、原始连接信息、自定义解析逻辑时才使用它。直接使用Request获取客户端 IP/主机名示例文档给出的经典场景是在路径操作函数内部获取客户端的 IP 地址/主机名。仓库中对应的可运行示例位于 docs_src/using_request_directly/tutorial001_py310.pyfrom fastapi import FastAPI, Request app FastAPI() app.get(/items/{item_id}) def read_root(item_id: str, request: Request): client_host request.client.host return {client_host: client_host, item_id: item_id}只需在路径操作函数的参数列表中声明一个类型为Request的参数例如上面的requestFastAPI 就会自动把当前请求的Request对象注入到该参数中无需你做任何额外配置。注意上面示例同时做了两件事路径参数item_id: str仍然被 FastAPI 提取、校验、转换为str类型并标注进 OpenAPIrequest: Request则被原样注入用于在函数体内读取request.client.host获得对端主机名。启动后例如uvicorn docs_src.using_request_directly.tutorial001_py310:app请求/items/foo时会得到类似{client_host: 客户端地址, item_id: foo}的响应。混合声明其他参数文档中的提示tip特别强调在本例中我们是在请求参数之外额外声明了一个路径参数因此路径参数照常被校验、转换并写入 OpenAPI。你完全可以沿用同样的思路任意组合常规参数并额外取一个Request想要同时获得校验后的请求体Pydantic 模型 客户端地址两者可共存想要校验后的查询参数 原始 Cookie同样可行。凡是通过类型声明解析的参数都保留完整的校验与文档能力Request只会加进来不会破坏其他参数的既有行为。源码解读FastAPI 如何识别并注入 Request 参数从源码层面看声明Request类型参数即自动注入这一行为是由依赖分析阶段与运行阶段协同完成的。依赖分析阶段标记为特殊参数在 fastapi/dependencies/utils.py 的函数add_non_field_param_to_dependency中FastAPI 会逐个检查路径操作函数的参数注解。其中第一步就是对Request以及WebSocket、HTTPConnection、Response、BackgroundTasks、SecurityScopes这类非字段参数做短路识别def add_non_field_param_to_dependency( *, param_name: str, type_annotation: Any, dependant: Dependant ) - bool | None: if lenient_issubclass(type_annotation, Request): dependant.request_param_name param_name return True elif lenient_issubclass(type_annotation, WebSocket): dependant.websocket_param_name param_name return True elif lenient_issubclass(type_annotation, HTTPConnection): dependant.http_connection_param_name param_name return True # ...当参数注解是Request或其子类时它不会进入字段参数 → 校验模型 → 生成 OpenAPI schema的常规通道而是被记为dependant.request_param_name从而从校验与文档流程中脱离——这正是源码层面印证了直接读取不校验、不上文档这一特性。运行阶段把 request 放进解析结果在同一文件的solve_dependencies中fastapi/dependencies/utils.py一旦检测到dependant.request_param_name已设置就会把当前request直接放入解析结果的值字典if dependant.request_param_name and isinstance(request, Request): values[dependant.request_param_name] request请求处理入口从 scope 构造 Request在路由层 fastapi/routing.py每个请求到达时都会先从 ASGIscope构造出Request(scope, receive, send)实例随后调用solve_dependencies解析所有依赖待校验错误处理完毕后最终路径操作函数通过dependant.call(**solved_result.values)见 fastapi/routing.py、fastapi/routing.py 等分支以关键字方式被调用request参数因此得以注入函数体。测试验证注入生效且不影响 OpenAPI仓库自带的测试文件 tests/test_tutorial/test_using_request_directly/test_tutorial001.py 从两个维度验证了本页文档描述的行为运行时行为通过TestClient请求/items/foo断言返回200且响应体为{client_host: testclient, item_id: foo}证明Request成功注入request.client.host可读。OpenAPI 行为请求/openapi.json并做全量快照比对可以看到生成的 OpenAPIpaths中只有item_id这一个路径参数被列为in: path、required: true、type: stringRequest参数完全没有出现在 OpenAPI 文档中——这是直接访问 Request 不参与文档生成的直接证据。这个测试很好地演示了声明式参数与原始 Request 的分工item_id照常校验与文档化Request则安静地做它的幕后工具。使用建议与注意事项结合文档与源码给出几条务实建议能用声明式就用声明式路径/查询/请求体参数优先用类型声明以持续获得校验、类型安全与 OpenAPI 文档Request 用于补充信息客户端地址request.client.host/request.client.port、原始头、原始连接、需要手动解析的数据等才考虑直接访问Request保留文档边界意识从Request上取走并用于业务的数据不会自动出现在 OpenAPI 中如果这些数据需要入参校验与文档化应改回声明式写法或自行实现校验/文档补充可选导入方式既可从fastapi导入RequestFastAPI 提供的便捷入口也可直接from starlette.requests import Request二者为同一对象可按团队习惯选用。本指南在docs/目录下还提供了多种语言版本英文 docs/en/docs/advanced/using-request-directly.md、法文 docs/fr/docs/advanced/using-request-directly.md 等内容一致可作为团队内部多语言文档对照阅读。完整源码示例可在 docs_src/using_request_directly/tutorial001_py310.py 中查看并直接运行。/DSMLparameter /DSMLinvoke /DSMLtool_calls【免费下载链接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production项目地址: https://gitcode.com/GitHub_Trending/fa/fastapi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表