FastAPI 子应用挂载Mounts让多个独立 FastAPI 应用共享一个服务端口【免费下载链接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production项目地址: https://gitcode.com/GitHub_Trending/fa/fastapi在 FastAPI 中当你需要运行两个或更多完全独立的应用——各自拥有独立的 OpenAPI Schema 和独立的 Swagger 文档界面却又希望它们部署在同一个端口、同一个服务器进程下时可以使用子应用挂载Mount机制创建一个主应用Top-Level Application然后把一个或多个子应用挂载mount到指定路径下。本文基于 FastAPI 官方文档 Sub Applications – Mounts 展开并结合fastapi/applications.py的源码与教程测试用例讲解挂载的完整操作步骤、验证方法以及底层root_path机制的工作原理。读完本文后你将能够用app.mount()把独立 FastAPI 应用挂载到主应用的指定路径理解主应用与子应用各自的/docs、/redoc、/openapi.json端点如何自动生成且互不干扰从源码层面理解 ASGIroot_path如何自动传递挂载前缀使子应用的文档 UI 与 OpenAPIservers字段正确工作。什么是挂载Mounting挂载Mounting是指在一个特定路径下添加一个完全独立的应用程序。挂载完成后该路径下的所有请求都会被交给这个子应用由其内部声明的路径操作path operations来处理。这与在单个应用内使用APIRouterprefix不同挂载上去的是一个完整的FastAPI实例它有自己独立的OpenAPI Schema/openapi.json文档界面/docs与/redoc异常处理器、依赖覆盖、中间件等应用级配置。主应用与子应用之间不共享路由表互不可见对方的路径操作——这正是两个独立应用语义的关键。完整示例主应用 子应用官方教程的完整可运行代码位于 tutorial001_py310.py整个文件只有 19 行from fastapi import FastAPI app FastAPI() app.get(/app) def read_main(): return {message: Hello World from main app} subapi FastAPI() subapi.get(/sub) def read_sub(): return {message: Hello World from sub API} app.mount(/subapi, subapi)下面按官方文档的三个步骤拆解这段代码。第一步创建顶层Top-Level应用首先创建主应用app及其路径操作app FastAPI() app.get(/app) def read_main(): return {message: Hello World from main app}这里app是最终由 ASGI 服务器如 Uvicorn启动的入口应用它声明了一个GET /app端点。第二步创建子应用然后创建子应用subapi及其路径操作subapi FastAPI() subapi.get(/sub) def read_sub(): return {message: Hello World from sub API}注意subapi只是一个标准的 FastAPI 应用与任何普通应用没有区别区别仅在于它会被挂载到主应用上而不是直接作为服务入口。第三步把子应用挂载到主应用在顶层应用app上调用mount()把subapi挂载到路径/subapiapp.mount(/subapi, subapi)从此所有以/subapi开头的请求都会进入subapi由它自己的路由表处理例如/subapi/sub会命中read_sub函数。mount()方法继承自 StarletteFastAPI(Starlette)定义见 applications.py。从源码结构看Starlette 的mount实现只是委托给路由器def mount(self, path: str, app: ASGIApp, name: str | None None) - None: self.router.mount(path, appapp, namename)即在 ASGI 路由层面把整个子应用作为一个路由目标注册到指定前缀下。运行并验证自动生成的 API 文档使用uv运行 FastAPI CLI 开发服务器代码文件需在项目根目录下$ uv run fastapi dev INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRLC to quit)主应用的文档http://127.0.0.1:8000/docs打开http://127.0.0.1:8000/docs你会看到主应用的自动 API 文档其中只显示主应用自己的路径操作/app完全看不到子应用的内容。子应用的文档http://127.0.0.1:8000/subapi/docs再打开http://127.0.0.1:8000/subapi/docs你会看到子应用独立的 Swagger UI它同样只包含子应用自己的路径操作但所有路径都带上了正确的前缀/subapi即GET /subapi/sub。如果分别在这两个文档界面中尝试 Try it out两者都能正常工作——因为浏览器会直接与各自对应的那个应用或子应用通信。同理两个应用的openapi.json也是相互独立的主应用http://127.0.0.1:8000/openapi.json子应用http://127.0.0.1:8000/subapi/openapi.json仓库中的测试用例 test_tutorial001.py 精确验证了上述行为test_main断言GET /app返回{message: Hello World from main app}test_sub断言GET /subapi/sub返回{message: Hello World from sub API}test_openapi_schema_main断言主应用的/openapi.json中paths只包含/app且没有servers字段test_openapi_schema_sub断言/subapi/openapi.json中paths只包含/sub并且额外带有servers: [{url: /subapi}]。servers字段是 OpenAPI 3 规范中的服务器地址声明——测试快照证实了子应用的 Schema 自动注入了挂载前缀这让任何遵循 OpenAPI 规范的客户端工具都能把请求正确发往/subapi下的地址。技术细节root_path机制这是子应用挂载能开箱即用的核心。当你按上述方式挂载子应用时FastAPI 会借助ASGI 规范中的root_path机制自动把挂载路径传递给子应用子应用据此知道自己的文档 UI 应该使用哪个路径前缀。从源码可以确认这一链路的几个关键位置均在 applications.py 中1. ASGI 启动时写入root_path。应用作为 ASGI 可调用对象被调用时如果显式配置了root_path见下文构造函数参数会写入请求scopeif self.root_path: scope[root_path] self.root_pathapplications.py当应用是被上层 Starlette 路由器以 Mount 方式挂载时则由 ASGI 服务器/上层路由在把请求分发给子应用之前设置scope[root_path]为挂载前缀。2. 动态注入servers字段。在get_openapi生成 Schema 的入口处FastAPI 检查当前请求的root_path若非空则把它加到 Schema 的servers列表最前面root_path req.scope.get(root_path, ).rstrip(/) if root_path and self.root_path_in_servers: server_urls {s.get(url) for s in schema.get(servers, [])} if root_path not in server_urls: schema[servers] [{url: root_path}] schema.get(servers, [])applications.py这正是测试中子应用 Schema 出现servers: [{url: /subapi}]的原因。3. 文档 URL 本身也带上前缀。子应用的/docs与/openapi.json端点在响应前也会读取scope[root_path]并拼接前缀root_path req.scope.get(root_path, ).rstrip(/) openapi_url root_path self.openapi_url oauth2_redirect_url root_path oauth2_redirect_urlapplications.py因此 Swagger UI 中发起请求的 base URL 会正确指向/subapi/openapi.jsonTry it out 才能打到子应用。相关构造函数参数FastAPI()构造函数applications.py提供了两个与挂载/前缀直接相关的参数值得在子应用场景下了解参数默认值作用root_path显式声明应用部署的路径前缀写入scope[root_path]用于生成 OpenAPIservers及文档 URL。文档提示openapi_prefix已被弃用并改用root_path见 applications.py。root_path_in_serversTrue关闭后不会自动用root_path生成 OpenAPI 的servers字段见 applications.py。servers[]手动指定 OpenAPIservers列表当其为空时FastAPI 会依据root_path自动填充见 applications.py 的参数文档。对于通过mount()挂载的子应用通常不需要手动设置root_path——ASGI 分发过程会自动完成。root_path参数更适用于把应用部署在路径前缀之后的场景例如经过反向代理。嵌套挂载同样有效文档还指出子应用本身也可以再挂载它自己的子应用一切都能正确工作因为 FastAPI 会自动处理所有层级的root_path。也就是说app → /subapi → /subapi/inner这样的多级挂载中每一层的文档 UI 与 OpenAPI 都会获得正确的累积前缀。延伸阅读root_path的显式用法例如应用部署在反向代理路径前缀之后见官方文档 Hinter einem ProxyBehind a Proxy教程源码docs_src/sub_applications/tutorial001_py310.py行为验证测试tests/test_tutorial/test_sub_applications/test_tutorial001.py应用类源码fastapi/applications.py。小结能力说明app.mount(/subapi, subapi)把一个完整独立的FastAPI应用挂载到主应用的/subapi路径下独立 OpenAPI主应用/openapi.json与子应用/subapi/openapi.json各自独立生成互不包含对方端点独立文档 UI/docs与/subapi/docs两个 Swagger UI 可分别交互各自只列出本应用的路径操作自动root_pathFastAPI 借助 ASGIroot_path自动为子应用注入前缀文档 URL、Try it out的 base URL、OpenAPIservers字段均自动正确嵌套挂载子应用可继续挂载更深层子应用各层root_path自动叠加适用前提与限制挂载发生在同一进程内子应用是标准 ASGI 应用FastAPI或任意兼容ASGIApp的实例若你需要的是路由前缀共享同一个 OpenAPI Schema应使用APIRouter(prefix...)只有需要完全独立的应用边界独立 Schema、独立文档、独立生命周期与配置时才应使用本文介绍的mount方式。【免费下载链接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production项目地址: https://gitcode.com/GitHub_Trending/fa/fastapi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考