Skip to content

FastAPI、Starlette 和 Uvicorn 在构建 Python Web 服务中的各自作用和它们之间的关系。

想象一下你正在建造一辆高性能汽车:

  • Uvicorn (发动机): 这是 ASGI 服务器。
  • Starlette (底盘和核心系统): 这是一个轻量级的 ASGI 框架/工具包。
  • FastAPI (车身、内饰和高级功能): 这是一个基于 Starlette 构建的高性能 Web 框架。

现在我们分别详细说明:

1. Uvicorn (或类似的 ASGI 服务器,如 Hypercorn, Daphne)

  • 作用:ASGI 服务器 (ASGI Server)

  • 核心职责:

    1. 监听网络请求: Uvicorn 负责监听指定的 IP 地址和端口,等待 HTTP (或 WebSocket) 请求的到来。
    2. 将 HTTP 请求转换为 ASGI 消息: 当一个 HTTP 请求到达时,Uvicorn 将其解析并转换为 ASGI (Asynchronous Server Gateway Interface) 规范定义的一系列事件(字典格式)。ASGI 是一种标准接口,用于解耦 Web 服务器和 Python Web 应用程序/框架。
    3. 将 ASGI 消息传递给 ASGI 应用: Uvicorn 将这些 ASGI 事件传递给你用 Starlette 或 FastAPI 编写的 ASGI 应用程序。
    4. 接收 ASGI 应用的响应: 你的应用程序处理完请求后,会生成 ASGI 响应事件。
    5. 将 ASGI 响应转换为 HTTP 响应: Uvicorn 接收这些 ASGI 响应事件,并将它们组装成标准的 HTTP 响应,然后发送回客户端(例如浏览器)。
    6. 管理并发和异步: Uvicorn 基于 uvloop (libuv 的 Python 绑定) 和 httptools (Node.js 的 HTTP 解析器的 Python 绑定) 构建,能够高效地处理大量并发连接,并支持异步操作。
  • 简单来说: Uvicorn 是你的 Python Web 应用(无论是 Starlette 还是 FastAPI 应用)与外部世界(互联网、浏览器)之间的桥梁和执行者。它负责处理底层的网络通信和协议转换,让你的应用专注于业务逻辑。没有 ASGI 服务器,你的 ASGI 应用就无法运行并对外提供服务。

2. Starlette

  • 作用:轻量级 ASGI 框架/工具包 (Lightweight ASGI Framework/Toolkit)

  • 核心职责:

    1. 提供 ASGI 应用骨架: Starlette 本身就是一个 ASGI 应用程序。它实现了 ASGI 规范,能够接收来自 Uvicorn (或任何其他 ASGI 服务器) 的 ASGI 事件并作出响应。
    2. 核心 Web 功能: Starlette 提供了构建 Web 应用所需的基础工具和组件,包括:
      • 路由 (Routing): 将不同的 URL 路径映射到相应的处理函数。
      • 请求对象 (Request Objects): 封装了传入的 HTTP 请求信息(如 headers, body, query parameters)。
      • 响应对象 (Response Objects): 用于构建各种类型的 HTTP 响应(如 HTMLResponse, JSONResponse, PlainTextResponse, RedirectResponse)。
      • 中间件 (Middleware): 允许你在请求处理流程的特定点插入自定义逻辑(例如,认证、日志、CORS 处理)。
      • WebSocket 支持: 内建对 WebSocket 通信的支持。
      • 后台任务 (Background Tasks): 允许在发送响应后执行一些任务。
      • 模板渲染 (Templating): 支持 Jinja2 等模板引擎。
      • 静态文件服务 (Static Files): 方便地提供 CSS、JavaScript、图片等静态资源。
      • CORS, GZip, Session 等支持。
    3. 异步优先: Starlette 从头开始设计为异步的,充分利用 Python async/await 语法,以实现高并发性能。
  • 简单来说: Starlette 提供了一套构建 Web 应用(特别是 API)所需的核心积木。它非常轻量、快速,并且专注于提供必要的 Web 开发功能,而不引入过多额外的复杂性。你可以直接使用 Starlette 构建 Web 应用,如果你不需要 FastAPI 提供的额外功能(如下所述)。

3. FastAPI

  • 作用:高性能 Web 框架 (High-performance Web Framework for building APIs)

  • 核心职责:

    1. 构建于 Starlette 之上: FastAPI 使用 Starlette 来处理所有底层的 Web 部分(路由、请求/响应、中间件等)。这意味着 FastAPI 继承了 Starlette 的所有优点,包括高性能和异步支持。
    2. 数据校验和序列化 (基于 Pydantic): 这是 FastAPI 的核心亮点之一。它利用 Python 的类型提示 (Type Hints) 和 Pydantic 库:
      • 自动数据校验: 根据你在函数参数中定义的类型提示,FastAPI 会自动校验请求数据(如路径参数、查询参数、请求体 JSON)。如果数据不符合预期,会自动返回详细的错误信息。
      • 数据序列化/反序列化: 将传入的 JSON 数据转换为 Python 对象 (Pydantic 模型),并将从处理函数返回的 Pydantic 模型或 Python 字典自动转换为 JSON 响应。
    3. 自动 API 文档 (OpenAPI 和 JSON Schema): FastAPI 会根据你的代码(类型提示、路径操作函数等)自动生成符合 OpenAPI 规范 (以前称为 Swagger) 的 API 文档。这包括:
      • 交互式的 Swagger UI (通常在 /docs 路径)。
      • 备选的 ReDoc 文档 (通常在 /redoc 路径)。
      • 这使得 API 的测试、调试和与前端/其他团队的协作变得极其方便。
    4. 依赖注入系统 (Dependency Injection): 一个强大且易于使用的系统,用于管理和注入依赖项(例如,数据库连接、认证逻辑、共享配置)。这有助于编写更清晰、可测试和可维护的代码。
    5. 安全性与认证: 提供了易于集成的工具来处理常见的安全需求,如 OAuth2、JWT 令牌等。
    6. 编辑器支持和开发者体验: 由于大量使用类型提示,FastAPI 提供了极佳的编辑器自动补全和类型检查支持,显著提升开发效率和代码质量。
  • 简单来说: FastAPI 在 Starlette 提供的 Web 基础之上,添加了大量用于构建现代 API 的高级功能,特别是围绕数据处理、文档生成和开发者体验。它旨在让你能够以最少的代码量快速构建健壮、高性能且易于维护的 API。

总结与关系

  • Uvicorn 是一个服务器,它运行你的 ASGI 应用。它是执行环境。
  • Starlette 是一个基础框架/工具包,它提供了构建 ASGI 应用所需的核心 Web 功能。它本身就是一个 ASGI 应用。
  • FastAPI 是一个更高级别的框架,它基于 Starlette 构建,并在其基础上添加了数据校验、自动文档、依赖注入等强大功能,极大地简化了 API 开发。FastAPI 应用也是一个 Starlette 应用,因此也是一个 ASGI 应用。

它们的关系是层层构建的:

  1. 你的 FastAPI 应用本质上是一个配置好并添加了额外功能的 Starlette 应用
  2. 这个 Starlette 应用 (无论是直接创建的还是通过 FastAPI 创建的) 是一个 ASGI 应用
  3. Uvicorn (或其他 ASGI 服务器) 负责加载并运行这个 ASGI 应用,处理网络通信。

通常的使用流程:

  1. 你使用 FastAPI 编写你的 API 逻辑(定义路径操作、数据模型等)。
  2. FastAPI 内部使用 Starlette 来处理路由、请求/响应对象等。
  3. 你使用 Uvicorn 来启动你的 FastAPI/Starlette 应用,使其能够接收和响应来自网络的 HTTP 请求。

命令 uvicorn main:app --reload 中,main 是包含 FastAPI 实例的 Python 文件名,app 是在该文件中创建的 FastAPI 实例 (例如 app = FastAPI())。Uvicorn 会加载这个 app 对象作为 ASGI 应用来运行。

为什么ASGI应用不依赖于类似uvicorn的ASGI服务器也能运行?

这是一个非常好的问题,它触及了 ASGI 规范的核心。

严格来说,为了作为网络服务对外提供 HTTP/WebSocket 服务,ASGI 应用(如 FastAPI 或 Starlette 应用)确实需要一个 ASGI 服务器(如 Uvicorn, Hypercorn, Daphne)。

那么,为什么可能会产生“不依赖 ASGI 服务器也能运行”的错觉呢?这通常涉及到以下几种情况:

  1. 测试 (Most Common Reason):

    • 当你为 FastAPI 或 Starlette 应用编写单元测试或集成测试时,你通常会使用一个测试客户端。例如,Starlette 提供了 TestClient,FastAPI 也推荐使用它(因为它基于 Starlette),或者 httpx.AsyncClient 可以直接与 ASGI 应用交互。
    • 工作原理: 这些测试客户端并不启动一个真正的 HTTP 服务器去监听网络端口。相反,它们直接在内存中调用 ASGI 应用的 __call__ 方法 (或者等效的入口点),模拟 ASGI 服务器的行为。它们构造 ASGI scope 字典,提供模拟的 receive (用于发送请求体) 和 send (用于接收响应) awaitable callable。
    • 表现: 在测试代码中,你看起来就像是直接“运行”了你的应用并向它发送请求,但实际上是测试工具在扮演一个轻量级的、内存中的“伪服务器”角色。
    • 示例 (使用 Starlette 的 TestClient):
      python
      from starlette.applications import Starlette
      from starlette.responses import JSONResponse
      from starlette.routing import Route
      from starlette.testclient import TestClient
      
      async def homepage(request):
          return JSONResponse({"hello": "world"})
      
      app = Starlette(routes=[
          Route("/", homepage),
      ])
      
      # 这里没有 Uvicorn,但应用"运行"了
      client = TestClient(app)
      response = client.get("/")
      assert response.status_code == 200
      assert response.json() == {"hello": "world"}
      在这个例子中,TestClient(app) 并没有启动 Uvicorn。它直接与 app 这个 ASGI 应用对象交互。
  2. 直接调用 ASGI 应用 (理论上/调试中):

    • ASGI 应用本质上是一个可调用的对象(通常是一个实现了 async def __call__(self, scope, receive, send) 方法的类的实例,或者一个满足此签名的异步函数)。
    • 理论上,你可以手动构造 scope, receive, 和 send,然后直接调用你的 ASGI 应用。但这非常繁琐,通常只在深入理解 ASGI 协议或进行非常底层的调试时才会这样做。这并不能让它成为一个网络服务。
  3. 作为另一个 ASGI 应用的组件:

    • 一个 ASGI 应用可以被挂载 (mount) 到另一个 ASGI 应用中。例如,你可以将一个 Starlette 应用挂载到另一个 Starlette 应用的某个路径下。在这种情况下,外部的 ASGI 应用充当了内部应用的“调用者”,但最终还是需要一个 ASGI 服务器来运行最外层的应用。

核心区别:

  • 运行代码 vs. 提供网络服务
    • 你的 Python ASGI 应用代码当然可以在没有 Uvicorn 的情况下被 Python 解释器执行(例如,在测试中,或实例化对象)。
    • 但是,要让这个应用能够监听网络端口、接收来自互联网的 HTTP 请求、解析这些请求、然后发送 HTTP 响应回去,这个过程就需要一个 ASGI 服务器。

ASGI 服务器 (如 Uvicorn) 的关键作用:

  1. 网络监听: 打开服务器套接字 (socket),监听指定的 IP 和端口。
  2. 协议处理: 接收原始的 TCP 连接,解析 HTTP 协议 (或 WebSocket 协议)。
  3. ASGI 消息转换: 将解析后的 HTTP 请求信息(headers, method, path, body 等)打包成 ASGI scope 字典,并创建 receivesend awaitable callables。
  4. 应用调用: 使用上述 scope, receive, send 来调用你的 ASGI 应用。
  5. 并发管理: 使用异步 I/O (如 asyncio, uvloop) 高效处理大量并发连接。
  6. 生命周期管理: 处理应用的启动和关闭事件 (ASGI lifespan protocol)。

总结:

你可以执行和测试 ASGI 应用的代码逻辑而无需一个完整的 ASGI 服务器,通常是借助测试客户端。但是,要将其部署为一个实际的、可访问的 Web 服务,你必须使用一个 ASGI 服务器(如 Uvicorn)。服务器是应用与外部网络世界之间的桥梁。

所以,如果你的意思是“我的 FastAPI 代码可以在 PyCharm 里点击运行按钮(比如运行一个测试脚本)并得到结果”,那么是的,这不需要 Uvicorn 一直在后台运行。但如果你的意思是“我的 FastAPI 应用可以作为一个 Web API 被浏览器或 curl 通过 http://localhost:8000 访问”,那么你就一定需要像 Uvicorn 这样的 ASGI 服务器来运行它。