根本原因是go默认下载机制无重试逻辑,遇tcp中断即失败;需配置多级goproxy fallback、合理设置gosumdb及注意环境变量生效。

go mod download 为什么总在中途断掉?
根本原因不是你的网络“差”,而是 Go 默认的下载机制没有重试逻辑。一旦 TCP 连接被中断(比如 DNS 短暂超时、TLS 握手失败、代理响应延迟),go mod download 就直接报错退出,不会自动重试。你看到的 dial tcp: i/o timeout 或 read tcp: connection reset by peer 都属于这一类——它不区分“临时抖动”和“永久不可达”,一律当作失败处理。
用 GOPROXY fallback 组合提升容错能力
单靠一个代理源扛不住抖动,必须配置多级 fallback。Go 支持用逗号分隔多个代理地址,遇到前一个不可用时会自动尝试下一个,直到 direct(直连源站)为止。这不是“备选”,而是关键容错手段。
-
go env -w GOPROXY="https://goproxy.cn,https://mirrors.tuna.tsinghua.edu.cn/go/modules/,direct"—— 推荐组合:七牛源响应快,清华源同步稳,direct是最后兜底 - 避免只写一个代理(如
https://goproxy.cn),否则该源短暂不可用就会彻底失败 - 不要把
direct放最前面,否则失去代理加速意义;也不要漏掉它,否则代理全挂时无法降级 - 某些企业防火墙会拦截境外域名,此时
direct反而比海外代理更可靠,这就是 fallback 的真实价值
临时加 -v 和重试脚本绕过卡死
调试阶段别等命令自己恢复,主动加 -v 看清卡在哪一步,再结合简单 shell 脚本做有限重试:
- 执行
go mod download -v,观察最后成功拉取的模块名(比如github.com/sirupsen/logrus@v1.9.0) - 若失败,可针对性重试:
go get -v github.com/sirupsen/logrus@v1.9.0 - 写个三重循环脚本(不推荐长期用,但救急有效):
for i in {1..3}; do go mod download && break || sleep 2; done - 注意:
go mod tidy内部也调用download,所以同样适用上述策略
GOSUMDB=off 不是偷懒,而是应对校验服务不可达
很多中断其实发生在校验阶段,而非下载本身。当 sum.golang.org 因网络抖动无法响应时,Go 会卡在 verifying 步骤,表现为长时间无输出,最终报 checksum mismatch 或直接超时。这不是模块坏了,是校验请求发不出去。
- 开发环境可安全设为
go env -w GOSUMDB=off,跳过远程校验(本地go.sum文件仍生效) - CI/CD 或生产构建若需校验,建议换可信镜像源:
go env -w GOSUMDB=sum.golang.org+replace=gosum.io+ca=trusted - 切勿只关
GOPROXY而留着GOSUMDB,否则下载完成却在校验环节失败,浪费带宽
真正麻烦的不是配置本身,而是不同场景下三个变量(GOPROXY、GOSUMDB、GOPRIVATE)的组合效果——比如私有模块走 direct 时,GOSUMDB=off 才有意义;又比如 IDE 终端没同步环境变量,看着配置写了,实际没生效。这些细节不显眼,但决定了你是花 2 分钟搞定,还是折腾半小时还不明白哪错了。











