ARTICLE DETAIL

资讯详情

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

FastAPI 直接使用 Request 对象:获取客户端 IP 等原始请求信息的高级指南

FastAPI 直接使用 Request 对象:获取客户端 IP 等原始请求信息的高级指南 FastAPI 直接使用 Request 对象获取客户端 IP 等原始请求信息的高级指南【免费下载链接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production项目地址: https://gitcode.com/GitHub_Trending/fa/fastapi本篇指南聚焦 FastAPI 中的一个进阶用法当常规的路径参数、查询参数等声明式取值方式无法满足需求时如何在路径操作函数path operation function中直接注入并使用底层 Starlette 的Request对象。读完本文你将掌握Request的注入写法、它与声明式参数在校验 / 转换 / 文档化上的本质区别、如何与普通参数混用以及该能力在 FastAPI 源码与测试中的实现依据。本文内容对应仓库中的 docs/ko/docs/advanced/using-request-directly.md同源英文版见 docs/en/docs/advanced/using-request-directly.md。声明式取参与直接访问 Request两种思路在使用 FastAPI 的过程中我们通常是声明式地描述请求中需要的数据例如从以下位置取值路径作为路径参数请求头HeadersCookie查询参数、请求体等等。这样做的好处是只要把参数类型写对FastAPI就会自动完成三件事——校验数据、把数据转换为你声明的类型、为 API 自动生成文档OpenAPI / 交互式文档。但现实中存在一些无法用声明式表达、必须拿到整个请求的场景例如获取客户端的 IP 地址 / host 主机信息读取原始请求体字节流并按自有逻辑解析访问底层连接、ASGI scope 等 Starlette 层面暴露的细节。此时FastAPI 允许你直接注入并使用 Starlette 的Request对象。Request 直接取值意味着什么校验、转换与文档的边界理解这一特性时最关键的一点是Request对象与 FastAPI 的关系FastAPI本质上是在Starlette之上叠加了一层工具依赖注入、数据校验、OpenAPI 生成等。因此当你有需要时可以随时使用 Starlette 原生的Request对象。而直接使用Request也带来一个明确的边界效应如果你从Request对象直接读取数据例如直接读请求体body这些数据不会被 FastAPI 校验、转换也不会进入 OpenAPI 文档因此不会出现在自动生成的 API 交互界面中但是你在同一函数里用常规方式声明的其他参数例如以 Pydantic 模型声明的请求体依然会被校验、转换、注解并纳入 OpenAPI 文档。换句话说Request是一扇旁路——走它取到的数据脱离 FastAPI 的自动化管线而并行声明的普通参数完全不受影响。在特定场景如读取原始请求体做自定义签名验证、跟踪客户端来源下这种旁路正是你需要的灵活性。在路径操作函数中直接使用 Request获取客户端 IP / 主机仓库教程在 docs_src/using_request_directly/tutorial001_py310.py 给出了完整可直接运行的示例。假设我们需要在路径操作函数内部获取客户端的 IP 地址 / host 信息from 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}核心机制只有一行将路径操作函数的某个参数类型声明为RequestFastAPI 就会识别出这一意图并在调用该函数时把当前请求的Request实例注入到这个参数中示例代码中即高亮的item_id: str, request: Request签名行。上面的例子同时说明了Request最典型的用途——通过request.client.host读取连接对端的 host / IP。请求GET /items/foo后函数返回{client_host: testclient, item_id: foo}该行为在仓库测试 tests/test_tutorial/test_using_request_directly/test_tutorial001.py 中被验证测试断言请求/items/foo返回200且响应体恰为{client_host: testclient, item_id: foo}。与其他参数混用路径参数仍走完整管线值得强调的一个 tip在注入request参数的同时函数签名旁还声明了普通路径参数item_id: str。二者的处理是并行的、互不干扰的item_id作为路径参数照常被提取、校验、转换为声明的类型str并注解到 OpenAPI中request只负责把原始Request对象交给函数体不参与 OpenAPI 建模。所以你可以这样理解平时怎么声明参数就怎么声明额外再要一个Request即可。路径参数、查询参数、请求体模型等仍可全部共存于同一个函数签名中同时从容地访问原始请求。源码视角Request 是如何被识别与注入的从依赖注入的源码实现看Request属于一类特殊的非字段non-field类型注解。在 fastapi/dependencies/utils.py 中参数分析阶段add_non_field_param_to_dependency()见 fastapi/dependencies/utils.py会检查类型注解当它判断注解是Request的子类时会把参数名记录为dependant.request_param_name同理被特殊处理的还有WebSocket、HTTPConnection、Response、BackgroundTasks与SecurityScopes等类型。这也解释了为什么Request不会误入查询参数、请求体等常规解析管线在 fastapi/dependencies/utils.py 的analyze_param()中当注解命中上述类型且没有显式Depends时会走特殊分支不会被当作普通字段参数处理。进入运行期后solve_dependencies()负责实际的取值注入见 fastapi/dependencies/utils.pyif dependant.http_connection_param_name: values[dependant.http_connection_param_name] request if dependant.request_param_name and isinstance(request, Request): values[dependant.request_param_name] request elif dependant.websocket_param_name and isinstance(request, WebSocket): values[dependant.websocket_param_name] request也就是说一旦检测到函数声明了Request类型的参数FastAPI 就会在解析依赖后把当前请求对象放进参数值字典从而完成注入。测试佐证Request 不出现在 OpenAPI 参数里同一个测试文件的test_openapi用例进一步印证了前文Request 不参与 OpenAPI 文档的说法GET /openapi.json生成的 OpenAPI 中/items/{item_id}的parameters列表里只有路径参数item_id类型为string、必填为trueRequest本身并未被建模成任何 OpenAPI 参数或请求体。这正是文档化的内容仅来自声明式参数的直接证据。Request 从哪里来FastAPI 的便捷再导出在 FastAPI 中from fastapi import Request与from starlette.requests import Request在底层是同一个对象。仓库中的 fastapi/requests.py 内容极其精简纯粹是 Starlette 的再导出from starlette.requests import HTTPConnection as HTTPConnection # noqa: F401 from starlette.requests import Request as Request # noqa: F401也就是说FastAPI 直接提供Request仅仅是为了方便你开发者它的真实来源是 Starlette你也可以选择from starlette.requests import Request两者等价。同理fastapi/requests.py还再导出了HTTPConnection说明Request所属的类继承体系HTTPConnection→Request也一并暴露给了 FastAPI 用户。使用注意事项与最佳实践结合上文可以把Request的适用边界总结成如下几条实用建议优先使用声明式参数。只要数据可以建模为路径参数、查询参数、头部、Cookie 或 Pydantic 模型请求体就让 FastAPI 负责校验、转换与文档化这是默认且更稳妥的方式。只在确需原始信息时引入Request。典型场景包括读取客户端 host/IPrequest.client.host、按自定义规则消费原始请求体、以及访问 ASGI scope 层面的细节。自行承担原始数据的处理成本。凡是从Request直接取得的数据都不再有类型转换、校验与 OpenAPI 注解你需要在自己的业务代码里保证解析的正确性。Request与普通参数天然共存。可以在同一函数中既用 Pydantic 模型接收并校验请求体又注入Request获取连接级信息——两条管线互不冲突。类型注解务必正确。只有把参数类型声明为Request或其可见的子类形式FastAPI 的依赖解析器才会触发上述特殊注入分支声明为其他类型则会被当作常规参数处理导致行为完全不同。Request对象本身暴露了 headers、query params、path params、cookies、client、scope 等大量运行时细节若想深入掌握其完整属性与读取接口可继续研读 Starlette 官方对Request的文档说明并结合本仓库的 docs_src/using_request_directly/ 示例与 tests/test_tutorial/test_using_request_directly/ 测试做本地实验——动手跑一遍uvicorn并查看/openapi.json是验证本页所有结论最快的方式。【免费下载链接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production项目地址: https://gitcode.com/GitHub_Trending/fa/fastapi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表