internal不是私有包,而是Go工具链在编译期强制拦截跨模块import的路径校验机制:仅允许同一go.mod下且路径前缀匹配的代码导入,无运行时开销,需配合GO111MODULE=on和GOPRIVATE才能生效。

直接用 internal 目录 + GO111MODULE=on + GOPRIVATE 三件套,就能在不公开源码前提下安全推广内部模块——它不靠加密或混淆,而是靠 Go 工具链的路径校验和代理绕过机制双重拦截。
为什么 internal 不是“私有包”,但能拦住外部 import
internal 是 Go 构建工具(go build、go list)在解析 import 路径时强制执行的静态检查:只要 import 路径里含 /internal/,且导入方与被导入方位于不同模块,就直接报错 import "xxx/internal/yyy" is not allowed。
这意味着:
- 同模块内任意位置(比如
cmd/app或pkg/api)都能正常 importmycorp.com/internal/db - 外部模块(哪怕只是同事本地 clone 的另一个项目)只要没声明为同一
go.mod根,就根本无法 import 这个路径 - 没有运行时开销,也不影响反射或类型系统——它只在
go mod tidy和go build阶段起作用
GO111MODULE=on 和 GOPRIVATE 必须同时配齐
如果只设 GOPRIVATE=*.mycorp.com 却没开模块模式,go get 会退化到 GOPATH 模式,完全无视 internal 规则,还可能拉错包。
立即学习“go语言免费学习笔记(深入)”;
必须确保三项环境变量全部生效:
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
-
GO111MODULE=on:强制启用模块系统,禁用 GOPATH fallback -
GOROOT显式指向 Go 安装路径(如/usr/local/go),避免和GOPATH混淆 -
GO111MODULE=on和GOPRIVATE=*.mycorp.com缺一不可;若用 SSH 地址,还需配置git config --global url."git@mycorp.com:".insteadOf https://mycorp.com/
模块路径必须和 Git 地址严格对齐
Go 不支持“逻辑路径 → 私有地址”的自由映射。模块路径(如 mycorp.com/internal/logging)必须能被工具链解析成真实可访问的 Git URL。
常见失败点:
- Git 仓库地址是
https://git.mycorp.com/team/logging,但go.mod写的是module mycorp.com/logging→ 报unknown revision - 用了自定义域名(如
logging.local)却没配/etc/hosts+GOINSECURE=logging.local→ TLS 校验失败 - HTTPS 方式未配置凭据助手(
git config --global credential.helper store),或 token 权限不足(需read_package_registry)
测试代码可以且应该 import internal
别把测试写在 internal 外面再 mock——那样反而破坏封装边界。正确做法是把测试文件放在同目录下,例如:
mycorp.com/internal/logging/ ├── logger.go ├── logger_test.go // 可以直接 import "." 并测试所有函数 └── config.go
这样既能覆盖内部逻辑,又不会暴露给外部模块。CI 流程中跑 go test ./internal/... 就能验证全部内部实现,无需妥协可见性。
真正容易被忽略的是:一旦放进 internal,它就默认是模块内隐式 API 层——改函数签名、删文件、甚至移动目录结构,都会导致同模块其他包编译失败。它不是垃圾桶,是契约。

















