结论是用air而非fresh或gin;90%启动失败源于代码编译错误或root、build.bin与build.cmd路径及[watch]/[build]两节include_ext配置未对齐,需先确保go build通过再运行air。

直接说结论:用 air,别碰 fresh 或 gin;装完就跑不起来,90% 是代码编译失败或路径配错,不是工具问题。
go build 能过,air 才可能跑起来
看到 failed to build, error: exit status 2 别急着改 .air.toml。这几乎总是 Go 代码本身的问题:
-
undefined: xxx→ 缺变量、函数名写错,或没导出(首字母小写) -
import cycle not allowed→ A 包 import B,B 又 import A,用go list -f '{{.Imports}}' ./...查 -
cannot find module providing package→ 当前目录没有go.mod,air默认从含go.mod的目录启动
实操建议:先在终端执行 go build,确认无红字报错,再让 air 接管。
air 启动失败最常见的三个配置硬伤
这三个字段必须对齐,漏一个就卡死:
-
root = "."必须指向含go.mod的目录(通常是项目根),不是cmd/api/main.go所在目录 -
build.cmd和build.bin路径必须严格一致:如果cmd = "go build -o ./tmp/main .",那bin就得是"./tmp/main",不能是"tmp/main"或"./main" -
include_ext要在[watch]和[build]两节都写,比如想监听config.yaml,就得同时加["go", "yaml"],漏一节都不触发
顺带一提:tmp_dir = "./tmp" 建议固定,并加进 .gitignore;delay = 1000 别乱调成 200,否则可能读到半截文件。
Colly 是一个用于 Go 语言的快速开源爬取和爬虫框架。它适用于从简单的页面提取到异步爬虫处理大量页面集合,支持请求回调和结构化解析。
fork/exec ./tmp/main: permission denied 怎么修
这是 macOS/Linux 上最典型的执行失败,根源不是权限策略,而是二进制没执行位或路径不一致:
- 把
build.cmd改成"go build -o ./tmp/main . && chmod +x ./tmp/main" - 检查
./tmp目录是否可写:ls -ld ./tmp,不行就chmod 755 ./tmp - 如果用了 NFS 或某些容器挂载,可能 strip 权限,这时用绝对路径更稳:
build.bin = "/full/path/to/tmp/main"
注意:air 发 SIGTERM 杀旧进程,但 Go 不会自动响应。没写 http.Server.Shutdown(),旧进程僵死后端口就被占着,ps aux | grep 还找不到它——只留个 socket 占位符。
改 config.yaml 或模板文件,真没必要靠 air 重启
air 的定位是代码热重载,不是配置热加载。改 YAML 后希望立刻生效,靠杀进程是粗暴且不可靠的:
- 用
viper.WatchConfig()只注册监听,必须在回调里手动调viper.ReadInConfig()和viper.Unmarshal() - 配置值要用
atomic.Value存指针,业务代码统一通过conf.Load().(*Config)读取,禁止缓存旧指针 - 数据库连接池大小这类运行时参数,得调
db.SetMaxOpenConns()才生效;HTTP 超时等底层参数根本没法热更
真正容易被忽略的是:热重载解决“代码改了要不要重启”,配置热加载解决“配置改了要不要重新初始化组件”。两者触发时机、作用范围、并发安全要求完全不同,混用只会埋坑。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










