air默认不重启是因为未监听到修改文件,需确保在go.mod根目录运行、root设为"."、watch显式包含子目录及非go扩展名,并校准build.bin与build.cmd路径。

air 默认不重启,不是工具坏了,而是它根本没监听到你改的文件——绝大多数“热重启失效”问题,都卡在这一步。
为什么改了 main.go 没反应?工作目录和 root 路径对不上
你在 cmd/api/ 目录下执行 air,但项目根目录(含 go.mod)其实在上层,air 就只会扫描当前目录,压根找不到 internal/ 或 pkg/ 里的代码。
- 必须在
go.mod所在目录运行air,不是main.go所在目录 -
root = "."在.air.toml中必须指向该目录;写成绝对路径(如/home/user/myapp)会导致换机器后失效 - 如果项目结构是
cmd/app/main.go+internal/handler/,需在[watch]下显式加include_dir = ["./", "./internal/", "./cmd/"],单写./在某些版本下不递归扫描子目录
air 启动报 exec: "./tmp/main": file does not exist 怎么办?
这不是编译失败,是 air 找不到二进制——build.bin 和 build.cmd 输出路径没对齐。
-
build.cmd = "go build -o ./tmp/main ."→build.bin必须严格写成"./tmp/main"(注意开头的.和斜杠) - Windows 用户别用反斜杠:
cmd\api\main.go是错的,要写cmd/api/main.go - Linux/macOS 上若
./tmp目录不可写,或 NFS 挂载 strip 了执行位,加&& chmod +x ./tmp/main到build.cmd更稳
改了 config.yaml 或 templates/index.html 为啥不重启?
air 默认只监听 .go 文件,.yaml、.html、.tmpl 都不在白名单里——这不是 bug,是设计如此。
- 必须在
[watch]和[build]两个 section 都配include_ext = ["go", "yaml", "yml", "html", "tmpl"];漏掉任意一个 section 都不生效 - 加太多后缀有代价:Linux inotify 句柄有限(默认 8192),大项目容易触发
inotify limit reached - 模板类文件建议用
embed.FS+ 代码变更触发重建,而非靠重启——更干净,也避免 HTTP 连接复用导致旧逻辑残留
重启后请求还是走旧逻辑?HTTP keep-alive 残留进程
浏览器或 curl 复用 TCP 连接,而旧进程还没完全退出,内核把请求转给了它,造成“改了没生效”的假象。
- 开发阶段启动 HTTP server 时加
srv.SetKeepAlivesEnabled(false) - 测试时用
curl -H "Connection: close" http://localhost:8080,比刷新浏览器靠谱 - Windows 下高频保存易触发文件锁,
build.delay = 1000给旧进程释放句柄留缓冲,别设低于 500
air 的核心约束很朴素:它只管“杀旧进程、跑新二进制”,不处理 graceful shutdown、不接管模板热加载、也不解决连接复用。这些得靠你代码里补全,而不是指望配置多加几行就万事大吉。golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











