国内 Go 模块下载慢的根本原因是默认代理 proxy.golang.org 不可达,必须同时满足三个条件:GOPROXY=https://goproxy.cn,direct 正确设置并被子进程继承、,direct 不可省略且置于末尾、GONOPROXY 显式排除私有路径;否则仍会 fallback 至不可达代理导致超时或失败。

国内环境下 Go 模块下载慢,不是你网络差,而是默认代理 proxy.golang.org 根本不可达——DNS 污染、TLS 握手超时、连接复用失败会触发重试退避,表现就是 go mod download 卡在某个模块几秒不动,最后报 dial tcp: i/o timeout 或 context deadline exceeded。真正起效的配置,必须同时满足三个条件:GOPROXY 正确设置并被子进程继承、,direct 不可省略、私有路径通过 GONOPROXY(而非仅 GOPRIVATE)显式排除。
为什么设了 GOPROXY=https://goproxy.cn,direct 还是走 proxy.golang.org
根本原因不是命令没运行成功,而是 Shell 启动新 go 进程时没把该变量导出到子进程环境里。IDE、CI、Docker 构建等场景尤其常见。
- 验证方式:运行
go mod download -x github.com/gin-gonic/gin@v1.9.1,看日志中实际请求的是哪个地址;若仍见https://proxy.golang.org/,说明未生效 - 临时修复:Linux/macOS 执行
export GOPROXY=https://goproxy.cn,direct,PowerShell 执行$env:GOPROXY="https://goproxy.cn,direct" - 持久生效:执行
go env -w GOPROXY=https://goproxy.cn,direct后,必须重启终端或source ~/.zshrc(或对应 shell 配置),否则子进程读不到 - 注意逗号前后不能有空格,
https://goproxy.cn, direct会失效
,direct 为什么必须写在末尾且不能省
direct 不是“可选兜底”,而是私有模块拉取成功的必要条件。漏掉它,所有未被代理识别的模块都会直接失败,而不是 fallback。
- 现象:公司内网 Git 地址如
git.example.com/internal/lib报not found或checksum mismatch - 原因:
GOPROXY=https://goproxy.cn(无,direct)会让 Go 强制把所有模块都扔给镜像站;而goproxy.cn无法处理 SSH 认证、Basic Auth 或内网 DNS 解析 -
direct必须放在逗号分隔列表末尾,否则后续代理不会被尝试;例如http://nexus.example.com/,direct,https://goproxy.cn是错的 - 如果公司用了 Nexus/Artifactory 自建代理,应把它放最前:
go env -w GOPROXY="http://nexus.example.com/repository/goproxy/,https://goproxy.cn,direct"
私有模块拉不到?GONOPROXY 和 GONOSUMDB 必须同步配
GOPRIVATE 只影响校验行为(跳过 sum.golang.org 查询),不绕过代理;真正让 Go 跳过代理直连源站的是 GONOPROXY。
立即学习“go语言免费学习笔记(深入)”;
- 查当前值:
go env GONOPROXY,若为空或不匹配你的私有域名,就会强制走代理并失败 - 正确做法:
go env -w GONOPROXY="git.internal.company.com,192.168.0.0/16",同时go env -w GONOSUMDB="git.internal.company.com,192.168.0.0/16"(值必须完全一致) - 通配符只支持子域名匹配,
*.corp.company可行,corp.company/internal不行 - 若已误配
GOPRIVATE干扰了请求,先清空:go env -u GOPRIVATE
Docker 构建中依赖下载仍慢?GOPROXY 必须显式写进 Dockerfile
CI/CD 环境中,Docker 守护进程不继承宿主机环境变量,不显式声明就直连 proxy.golang.org,国内必然超时。
- 在
Dockerfile开头加:ENV GOPROXY=https://goproxy.cn,direct - 依赖下载层必须前置且独立:
COPY go.mod go.sum ./→RUN go mod download,不要合并成一条命令 - 确保
go.sum没被.dockerignore误删(常见错误:写了**/go.sum) - 别用
--build-arg GOPROXY=...动态传入,容易漏配;也别在构建阶段挂载宿主机缓存目录,CI 路径不可靠
最容易被忽略的一点是:即使所有配置都对,只要 go.mod 文件本身频繁变更(比如每次提交都改版本号),Docker 构建缓存就永远无法命中 go mod download 层——这时优化代理只是治标,得先控制 go.mod 的变更节奏。


















