根本原因是air未正确识别入口文件或工作目录错误;需确保在main.go所在目录运行,配置root为含go.mod的路径、tmp_dir为./tmp、build.cmd适配go.work,windows注意路径分隔符,macos/linux注意权限与sip限制,程序须实现shutdown逻辑释放端口。

Go 项目用 air 热重载,为什么改了代码没反应?
根本原因通常是 air 没正确识别你的入口文件,或工作目录不对。它默认只监听 main.go,且必须在包含该文件的目录下运行;如果你项目结构是 cmd/myapp/main.go,直接在根目录跑 air 就不会触发重建。
- 确保终端当前路径是
main.go所在目录(不是项目根目录,除非main.go就在根) - 用
air -c .air.toml显式指定配置时,.air.toml必须存在且路径正确 - Windows 用户注意:路径分隔符写成
/或双反斜杠\,单反斜杠会解析失败 - 修改
.air.toml后要重启air进程,它不热加载自身配置
air 的 .air.toml 配置关键项怎么填?
多数人卡在 root、tmp_dir 和 build.cmd 三个字段——它们共同决定编译行为和产物位置。默认配置对多模块或带 go.work 的项目大概率失效。
-
root:设为项目根目录(含go.mod的路径),不是main.go所在目录 -
tmp_dir:建议设为./tmp并加到.gitignore,避免生成文件污染仓库 -
build.cmd:如果用了go.work,改成go run .;如果是标准模块,保持go build -o ./tmp/main . - 监听范围用
include_ext控制,比如加["go", "mod", "sum"],否则改了go.mod不会自动go mod tidy
Mac / Linux 下 air 报 fork/exec: operation not permitted 怎么办?
这是 macOS Gatekeeper 或 Linux 安全策略拦截了 air 生成的临时二进制,尤其在启用了 SIP(System Integrity Protection)或使用了 brew install air 安装旧版本时高频出现。
- 优先用
go install github.com/cosmtrek/air@latest安装,绕过包管理器签名限制 - macOS 上确认
tmp_dir不在/tmp(SIP 会阻止执行),改用项目内./tmp - Linux 使用
systemd --user管理服务时,air无法 fork 子进程,此时必须切回终端直接运行 - 错误信息里如果带
permission denied,先ls -l ./tmp看权限,确保可执行位存在
为什么 air 重载后端口被占用,但 ps aux | grep myapp 找不到进程?
因为 air 杀旧进程靠的是发送 SIGTERM,而你的 Go 程序如果没有注册信号处理或 http.Server.Shutdown,就会变成僵死进程,端口实际未释放。
立即学习“go语言免费学习笔记(深入)”;
- 在
main()里加signal.Notify捕获os.Interrupt,调用server.Shutdown - 检查
build.bin字段是否指向了错误的可执行路径,导致air杀错进程 - 开发时可临时在
.air.toml加build.delay = 1000(毫秒),给旧进程留出关闭时间 - 实在不行,手动
lsof -i :8080(Mac)或ss -tulpn | grep :8080(Linux)找 PID 并kill -9
真正麻烦的从来不是装不上 air,而是它悄悄跳过你没写的 shutdown 逻辑,让端口卡死、日志断流、甚至连接池泄漏——这些都不会报错,只会让你以为是网络问题。










