air是当前go项目最顺手的热重载工具,因其开箱即用、配置轻量、响应快,支持多样化项目结构,且终端输出清晰、启动与重建流程直观。

用 air 就够了,它对 Go 项目开箱即用、配置轻量、响应快,比 modd 更省心,也比 Revel 内置热重载更通用(不绑定框架)。
为什么 air 是当前最顺手的选择
Go 项目结构越来越多样:单模块、多 cmd/ 子命令、go.work 多模块 workspace、clean-arch 分层目录……air 的默认行为能覆盖 80% 场景,而 modd 需手动写 modd.conf 规则,Revel 只适用于 Revel 项目。更重要的是:air 启动后终端输出清晰(watching → building → running),改完保存立刻看到效果,没有中间状态卡顿。
常见错误现象:
- 改了
internal/handler/user.go没反应 → 实际上air默认只监听main.go所在目录及子目录,若你的main.go在cmd/api/main.go,就必须在该目录下运行air,不能在项目根目录直接跑 - 终端报
fork/exec: operation not permitted→ macOS SIP 或 Linux 安全策略拦截了./tmp下生成的临时二进制,需确认./tmp目录有执行权限且未被隔离
air 必须配对的三个关键配置项
多数人卡在这三项上,导致热重载失效或构建产物错位。它们不是可选,而是决定“编什么”“放哪”“从哪启”:
-
root:必须设为含go.mod的路径(通常是项目根目录),不是main.go所在目录;否则go build会找不到 module -
tmp_dir:建议固定为./tmp,并加到.gitignore;air会把构建产物放这里,路径错误会导致找不到可执行文件进而杀错进程 -
build.cmd:标准模块用go build -o ./tmp/main .;若项目用了go.work,必须改成go run .,否则构建失败静默跳过
其他实用配置:
使用 Python 脚本下载 Docker 镜像并打包为 tar 文件。用户说“下载镜像”“拉取镜像”“pull xxx”“帮我下载 nginx 镜像”等时触发。支持 SOCKS5 代理直连(推荐)和国内镜像站加速两种模式。
-
include_ext = ["go", "mod", "sum"]:加上mod和sum,改了依赖能自动go mod tidy -
exclude_dir = ["vendor", "node_modules", ".git"]:避免误触发无关变更
端口被占、进程僵死?多半是没写 Shutdown
air 发 SIGTERM 杀旧进程,但 Go 默认不处理这个信号。如果你没在 main() 里注册 os.Interrupt 并调用 http.Server.Shutdown(),旧进程不会优雅退出,端口就一直被占着——而 ps aux | grep 还真找不到它,因为进程已变成僵尸态,只留个 socket 占位符。
必须补上的逻辑(以 HTTP server 为例):
server := &http.Server{Addr: ":8080", Handler: router}
go func() {
if err := server.ListenAndServe(); err != http.ErrServerClosed {
log.Fatal(err)
}
}()
// 等待中断信号
quit := make(chan os.Signal, 1)
signal.Notify(quit, os.Interrupt)
<p>漏掉这段,<code>air</code> 每次重载都会悄悄积累一个僵死进程,几分钟后开发环境就卡死。</p>
<h3>Docker 环境下热重载要绕开两个坑</h3>
<p>容器内跑 <code>air</code> 不是简单把命令塞进 <code>ENTRYPOINT</code> 就行。核心问题是:容器启动时工作目录和文件挂载点必须对齐,且 <code>air</code> 需要能监听到宿主机的文件变更事件。</p>
- 挂载方式必须用
bind mount(-v $(pwd):/app),不能用copy或build context,否则宿主机改代码,容器内根本收不到 fsnotify 事件 - 确保容器内
air启动路径是/app(即挂载点),且root = "/app"、tmp_dir = "/app/tmp",否则构建产物路径错乱,air找不到新二进制去替换 - Linux 容器需加
--privileged或--cap-add=SYS_ADMIN(仅限开发环境),否则某些内核事件监听可能被限制
真正容易被忽略的一点:Docker Desktop for Mac/Windows 的文件系统事件转发有延迟,有时改完保存,容器内要等 1–2 秒才触发重建。这不是 bug,是虚拟化层的固有限制,别把它当配置错误来回折腾。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










