Uvicorn 启动 FastAPI 报 ModuleNotFoundError 是因找不到 main.py 文件或其中未定义 app 变量;--reload 仅监听 .py 文件时间戳变化;本地开发用 --host 127.0.0.1 更安全,局域网访问需 --host 0.0.0.0;启动成功不等于接口可用,须手动测试 / 和 /docs。

Uvicorn 启动 FastAPI 项目,核心就一条命令:uvicorn main:app --reload,但拼错模块名、变量名、路径或环境配置错误,都会导致「找不到应用」或「启动后无法访问」。
为什么 uvicorn main:app 会报 ModuleNotFoundError?
这不是 Python 导入失败,而是 Uvicorn 在当前工作目录下找不到 main.py 文件,或文件里没定义名为 app 的变量。
-
main是模块名(即 Python 文件名,不含.py),必须和当前终端所在目录下的文件名完全一致(区分大小写,比如Main.py≠main.py) -
app是变量名,必须是main.py中通过app = FastAPI()创建的顶层变量,不能在函数/类/条件块内定义 - 如果文件不在当前目录,需用相对/绝对路径导入:例如
src.main:app(前提是src/是 Python 包,含__init__.py) - 终端执行命令前,先运行
ls main.py(macOS/Linux)或dir main.py(Windows)确认文件存在
--reload 开发模式下哪些改动会触发重载?
Uvicorn 默认只监听 .py 文件变更,但实际生效依赖两个条件:Python 源码变动 + 文件时间戳更新。常见失效场景:
Uvicorn 0.52.1 是 Python ASGI Web 服务器,提供异步应用服务及 WebSocket 支持,常用于 FastAPI、Starlette 等应用的开发和部署。本下载为官方 PyPI 通用 wheel 包,可使用 pip 安装,并由包管理器处理所需依赖。
- 编辑器保存时未真正写入磁盘(如 VS Code 的「延迟保存」或「暂存区预览」),可关掉「Auto Save」并手动
Ctrl+S - 使用 WSL 或远程开发时,文件系统挂载方式导致时间戳未更新,建议在 WSL 内部终端执行命令,而非 Windows 命令行
- 修改了
pydantic模型或路由装饰器参数(如@app.post("/v1/users", tags=["user"])),这些属于代码逻辑,会被检测到;但修改 OpenAPI 文档描述字符串(description=...)不会触发重载 - 不建议在生产环境加
--reload,它会启用watchfiles监控进程,增加资源开销且不安全
本地调试时,host 和 port 怎么设才不踩坑?
默认 uvicorn main:app --reload 绑定的是 127.0.0.1:8000,这会导致某些情况无法访问:
- 想用手机或局域网其他设备访问,必须显式指定
--host 0.0.0.0(不是*或空字符串) - 端口被占用时,不要直接改
--port然后硬上,先查占用:lsof -i :8000(macOS/Linux)或netstat -ano | findstr :8000(Windows) - Docker 容器内运行时,
--host 0.0.0.0是必须的;但本地开发用--host 127.0.0.1更安全,防止局域网扫描暴露接口 - 浏览器访问请认准控制台输出的那行:
INFO: Uvicorn running on http://127.0.0.1:8000—— 不要凭记忆输错协议(http不是https)或端口
如何让 uvicorn.run() 脚本方式和命令行行为一致?
直接运行 python main.py 时,如果用了 uvicorn.run(...),必须保证参数对齐,否则热重载、日志级别、绑定地址都可能不一致:
- 脚本中调用
uvicorn.run()时,reload=True必须配合reload_dirs=["."](尤其在子目录结构下) -
debug=True不等于--reload,它只影响 FastAPI 内部异常页面,不影响重载逻辑 - 避免混用:不要在命令行加
--reload,同时又在脚本里写reload=True,Uvicorn 会报ValueError: reload cannot be used with reload_dirs - 推荐统一用命令行方式启动,脚本里只保留
app = FastAPI()和路由定义,保持纯净
最常被忽略的一点:Uvicorn 启动成功后,它只是「开始监听」,并不验证路由是否真的能响应。哪怕你写了 @app.get("/api/user"),但没定义参数类型或返回值,接口仍能启动——直到你用 Postman 或浏览器请求时才抛出 500 错误。所以启动后务必手动测一个根路径 /,再看文档页 /docs 是否能打开。

















