写过 Python Web 服务的人大概都有过这样的经历,写完一个 FastAPI 应用后,脑子里要先回忆一遍 uvicorn 的启动参数,--reload 加不加、--host 写成什么、模块路径怎么拼。这些琐碎的记忆负担看似不大,但积少成多也挺烦人。FastAPI 团队后来推出了官方命令行工具 FastAPI CLI,把这些事情打包成两条简单命令,一条用于开发调试,一条用于生产部署 。
这篇文档会把 FastAPI CLI 的方方面面捋一遍,从安装到两大核心命令的区别,再到它背后是怎么自动找到你的应用代码的,尽量讲得透彻又不啰嗦。
FastAPI CLI 是什么
FastAPI CLI 本质上是一个叫 fastapi 的命令行程序,用来运行你的 FastAPI 应用、管理项目结构,未来还会承载更多项目管理功能 。它并不是一个独立安装的软件包,而是内置在 fastapi-cli 这个子包里。只要你用带 standard 附加选项的方式安装 FastAPI,这个命令就会自动出现在你的终端里。
bash
pip install "fastapi[standard]"
装完之后,终端里敲一下 fastapi --help 就能看到这个工具已经就位了 。它的底层跑的其实是 Uvicorn,也就是那个高性能、生产级别的 ASGI 服务器,FastAPI CLI 只是在它外面包了一层更友好的外壳,帮你把常用参数、应用发现逻辑、开发生产模式的差异都处理好了 。
打个比方,如果说 Uvicorn 是一台手动挡汽车,那 FastAPI CLI 就是给它加了自动挡,日常开车的时候你不需要每次都想着离合器和挡位,直接踩油门就能走。
核心命令一 fastapi dev 开发模式详解
写代码调试阶段用的就是这个命令。
bash
fastapi dev main.py
跑起来之后终端会打印一堆友好的提示信息,告诉你它在哪个目录搜索文件、从哪个模块导入了 app 对象、服务跑在哪个地址上,长这样
text
FastAPI Starting development server 🚀
Searching for package file structure from directories with __init__.py files
Importing from /home/user/code/awesomeapp
module 🐍 main.py
code Importing the FastAPI app object from the module with the following code
from main import app
app Using import string: main:app
server Server started at http://127.0.0.1:8000
server Documentation at http://127.0.0.1:8000/docs
tip Running in development mode, for production use: fastapi run
这段输出其实把它做的事情交代得很清楚,包括它怎么找到你的 app、用什么导入路径、监听在哪个端口。
fastapi dev 有几个默认设定值得记住
- 自动重载默认开启,代码一改服务自动重启,方便调试,但这个功能比较吃资源,稳定性也稍逊一筹,所以只建议在本地开发用
- 默认监听地址是 127.0.0.1,也就是本机回环地址,只有你自己的电脑能访问,外部设备连不进来,这其实是个安全考量,开发阶段没必要把服务暴露到公网上
- 自动设置环境变量 FASTAPI_ENV 为 development,如果你的代码里已经手动设置过这个变量,CLI 不会覆盖它,这样你可以在应用启动逻辑里根据这个变量做区分处理,比如开发环境打印更详细的日志
关于 FASTAPI_ENV,官方约定的取值一般是 development 和 production 两种,不过要提醒一句,fastapi run 目前并不会自动帮你把这个变量设成 production,如果你的应用需要靠这个变量判断生产环境,得自己手动设置 。
核心命令二 fastapi run 生产模式详解
上线部署的时候切换成这条命令就行。
bash
fastapi run main.py
fastapi run 和 fastapi dev 的设计理念完全不同,它默认就是奔着生产环境去的
- 自动重载默认关闭,生产环境代码不会频繁变动,开着热重载反而浪费资源
- 默认监听地址是 0.0.0.0,意味着所有网络接口都能访问,这样部署在服务器上外部用户才能真正连接到你的服务
官方文档里对这条命令的定位说得很直接,简单讲,用 fastapi run 来运行你的 FastAPI 应用就对了,这通常也是容器化部署(比如用 Docker)里最常见的启动方式 。
fastapi dev 与 fastapi run 对比一览
两条命令看着相似,实际定位完全不同,下面这张表梳理一下核心差异。
| 对比维度 | fastapi dev | fastapi run |
|---|---|---|
| 使用场景 | 本地开发调试 | 生产部署 |
| 自动重载 | 默认开启 | 默认关闭 |
| 默认监听地址 | 127.0.0.1(仅本机) | 0.0.0.0(对外开放) |
| FASTAPI_ENV | 自动设为 development | 不做修改,需手动设置 |
| 性能与稳定性 | 侧重开发体验 | 侧重生产稳定性 |
简单一句话总结,本地开发用 dev,服务器上线用 run,别搞反了就行。
下面用一张流程图直观感受一下启动过程中发生了什么。
应用自动发现机制 它是怎么找到你的 app 的
这可能是 FastAPI CLI 最讨喜的一个设计。你不需要像用 Uvicorn 那样手动写出 main:app 这种导入字符串,CLI 会自己去猜 。
它的逻辑大致是这样的,从你传入的文件路径开始,向上一层层查找目录,看看有没有 __init__.py 文件,用这个来判断你的项目是不是一个 Python 包结构,进而推算出正确的模块导入路径。找到模块之后,它会在里面扫描类型是 FastAPI 的变量,如果发现一个叫 app 的变量,直接拿来用,如果模块里只有一个 FastAPI 实例但名字不叫 app,它也会智能地选中它 。
如果你什么参数都不传,直接在项目根目录敲 fastapi dev,它甚至会自己去找 main.py 或者 app.py 这样的常见入口文件。
用一张图表示这个查找流程会更直观。
配置入口点 entrypoint
有些项目结构比较特殊,自动发现机制猜不准的时候,就需要手动告诉 CLI 应用入口在哪。官方给出了两种方式 。
方式一,在 pyproject.toml 里配置
toml
[tool.fastapi]
entrypoint = "app.main:app"
这样配置之后,之后再运行 fastapi dev 或 fastapi run,它会优先读取这个配置里的入口点,不用每次手动指定。
方式二,通过命令行参数直接指定
bash
fastapi dev --entrypoint app.main:app
或者更传统的做法,直接把路径当作导入字符串传进去
bash
fastapi dev app/main.py
两种方式各有适用场景,团队协作项目建议用 pyproject.toml 的方式固定下来,这样每个人在本地跑起来的命令都是统一的,不容易因为路径写错而踩坑。
部署在反向代理之后
如果你的 FastAPI 服务前面挂了一层 Nginx 或者其他反向代理,客户端的真实 IP 和协议信息会被塞进 X-Forwarded-* 这类请求头里。这时候需要告诉 FastAPI CLI 该信任哪些来源的转发头,用的是 forwarded-allow-ips 这个选项 。
bash
fastapi run main.py --forwarded-allow-ips="*"
除此之外,如果你的应用被部署在某个子路径下面,比如通过代理把 /api 前缀转发到你的服务上,还可以配合 --root-path 选项让 FastAPI 生成的 OpenAPI 文档和链接都能正确带上这个前缀。这一类参数在多层网关架构下会经常用到,尤其是微服务集群里网关统一收口的场景。
常用可选参数速查
除了上面提到的这些,FastAPI CLI 还支持不少常见的启动参数,整理成表方便查阅。
| 参数 | 作用 | 常见于 |
|---|---|---|
--host |
指定监听的 IP 地址 | dev / run |
--port |
指定监听端口,默认 8000 | dev / run |
--reload / --no-reload |
手动开关自动重载 | dev / run 均可覆盖默认值 |
--workers |
设置工作进程数量,提升并发能力 | run(生产场景常用) |
--root-path |
配置反向代理场景下的路径前缀 | run |
--proxy-headers |
是否信任代理转发的请求头 | run |
--entrypoint |
手动指定应用导入路径 | dev / run |
--workers 参数值得单独说一句,生产环境里一个进程往往吃不满多核 CPU 的性能,通过增加工作进程数,可以让多个 Uvicorn worker 并行处理请求,显著提升吞吐能力,这也是为什么这个参数几乎只出现在 fastapi run 的推荐用法里。
从零跑一个例子
理论说了不少,落地看看实际操作。假设项目结构长这样
text
awesomeapp/
├── main.py
└── requirements.txt
main.py 里写一个最简单的应用
python
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"message": "Hello FastAPI CLI"}
进入这个目录,直接跑
bash
fastapi dev main.py
浏览器打开 http://127.0.0.1:8000/docs,就能看到自动生成的交互式 API 文档界面了。这套自动文档功能是 FastAPI 框架本身自带的,CLI 只是帮你把服务顺利跑起来而已。
等到要上线部署的时候,把命令换成
bash
fastapi run main.py --host 0.0.0.0 --port 80 --workers 4
配合 Docker 或者其他容器编排工具,这条命令基本就能覆盖大多数中小型项目的生产部署需求 。
一点实践建议
从个人踩坑经验来看,有几点值得提前留意。
项目结构复杂、涉及多层子包的时候,尽量不要依赖自动发现机制,老老实实在 pyproject.toml 里写清楚 entrypoint,省得团队里每个人跑起来的行为都不一样。
生产环境千万别用 fastapi dev,自动重载和调试模式在高并发场景下稳定性会打折扣,官方也明确提示过这一点,日志里那句 Running in development mode, for production use: fastapi run 不是随便写的提醒 。
如果应用逻辑里需要判断当前处于开发还是生产环境,别指望 fastapi run 会自动帮你设置 FASTAPI_ENV,这个变量目前只有 fastapi dev 会自动写入,生产环境需要自己在启动脚本或者容器环境变量里显式配置好 。
结语
FastAPI CLI 说到底解决的是一个体验问题,把原本需要记忆一堆 Uvicorn 参数、手动拼接导入字符串的琐碎操作,压缩成两条语义清晰的命令。开发阶段用 fastapi dev 图个方便快捷,上线部署切到 fastapi run 保证稳定安全,中间需要特殊配置的场景,靠 entrypoint 和一系列可选参数灵活调整。工具本身不复杂,但用顺手了确实能省不少心。
参考资料
FastAPI CLI 官方文档 fastapi.tiangolo.com/fastapi-cli...
fastapi/fastapi-cli GitHub 仓库 github.com/fastapi/fas...
FastAPI 官方教程 First Steps fastapi.tiangolo.com/tutorial/fi...
FastAPI 官方文档 Run a Server Manually fastapi.tiangolo.com/deployment/...
FastAPI 官方文档 Behind a Proxy fastapi.tiangolo.com/advanced/be...