createdtime 20211021
updatedtime 20211021
author venki.chen
一、是什么
1. 定义,是做什么用的?
定义:
- go mod能管理的依赖包的版本,能保证在不同地方构建,获得的依赖模块是一致的,集成在go tool中。go version >= 1.11,go1.13已经默认开启。
- 模块是相关Go包的集合。modules是源代码交换和版本控制的单元。go命令直接支持使用modules,包括记录和解析对其他模块的依赖性。modules替换旧的基于GOPATH的方法来指定在给定构建中使用哪些源文件。
参数说明:
序号 | 名称 | 说明 | 备注 |
---|---|---|---|
01 | CGO_ENABLED | 指明cgo工具是否可用的标识。 | set CGO_ENABLED=1 |
02 | GOARCH | 程序构建环境的目标计算架构。 | set GOARCH=amd64 |
03 | GOBIN | 存放可执行文件的目录的绝对路径。 | set GOBIN= |
04 | GOCHAR | 程序构建环境的目标计算架构的单字符标识。 | |
05 | GOEXE | 可执行文件的后缀。 | set GOEXE=.exe |
06 | GOHOSTARCH | 程序运行环境的目标计算架构。 | set GOHOSTARCH=amd64 |
07 | GOOS | 程序构建环境的目标操作系统。 | set GOOS=windows |
08 | GOHOSTOS | 程序运行环境的目标操作系统。 | set GOHOSTOS=windows |
09 | GOPATH | 工作区目录的绝对路径。 | set GOPATH=D:\WORKSPACE\Gopro\FK |
10 | GORACE | 用于数据竞争检测的相关选项。 | |
11 | GOROOT | Go语言的安装目录的绝对路径。 | set GOROOT=D:\WORKSPACE\Fighting\go |
12 | GOTOOLDIR | Go工具目录的绝对路径。 | set GOTOOLDIR=D:\WORKSPACE\Fighting\go\pkg\tool\windows_amd64 |
13 | GOPROXY | 设置拉取的代理。 | set GOPROXY=https://goproxy.cn,direct |
14 | GO111MODULE | go modules 功能的开关。 | set GO111MODULE=auto |
15 | GOINSECURE | go 动态获取模块的请求方式,默认HTTPS,为1时则为http。 | set GOINSECURE = 1 |
16 | GOSUMDB | 设定的module校验数据库。 | set GOSUMDB=.yewifi.com,.yunpiaoer.com,*.yunpiaoer.cn |
17 | GONOSUMDB | 设定的module不需要校验的数据库。 | set GONOSUMDB = *.yewifi.com |
18 | GONOPROXY | 不通过代理GOPROXY 拉去代码,直接通过传统的VCS(版本控制系统)拉取代码。 | set GONOPROXY=*.yewifi.com |
19 | GOPRIVATE | 设置GOPRIVATE来跳过私有库。 | go env GOPRIVATE=.gitlab.com,.gitee.com |
20 | GOVCS | 这是 GO1.16 版本才添加的,其主要作用是指定哪些模块使用哪些 VCS。 | go env GOVCS= |
补充说明:
-
GOPROXY
- set GOPROXY=https://mirrors.aliyun.com/goproxy/#设置拉取的代理。七牛云的是:https://goproxy.cn,direct
- set GOPROXY=file://本地路径 # 也可以从本地加载。
-
GONOPROXY
- GONOPROXY,基于前缀的匹配方式运行,上图中指定了gitlab.com,也就是所有 gitlab.com 上的代码,不从 GOPROXY 服务器上去获取,全部通过传统 VCS 方式,直接去原代码服务器上拉取。
-
GO111MODULE
- GO111MODULE=off,无模块支持,go命令行将不会支持module功能,寻找依赖包的方式将会沿用旧版本那种通过vendor目录或者GOPATH模式来查找。
- GO111MODULE=on,模块支持,go命令行会使用modules,而一点也不会去GOPATH目录下查找。
- GO111MODULE=auto,默认值,go命令行将会根据当前目录来决定是否启用module功能。这种情况下可以分为两种情形:
- 当前目录在GOPATH/src之外且该目录包含go.mod文件,开启模块支持。
- 当前文件在包含go.mod文件的目录下面。
-
GOINSECURE
- GO 默认会发送 HTTPS 请求,如果服务器想用 HTTP 协议,可以通过环境变量 GOINSECURE 来处理,当 GOINSECURE 为 1 时,GO 就会使用 HTTP 协议。
-
GOSUMDB
- GOSUMDB(go checksum database)是Go官方为了go modules安全考虑,设定的module校验数据库,服务器地址为:sum.golang.org。
- 你在本地对依赖进行变动(更新/添加)操作时,Go 会自动去这个服务器进行数据校验,保证你下的这个代码库和世界上其他人下的代码库是一样的。
- module 验证:Go1.13 版本开始加入模块 SUM 验证机制,默认所有 go 模块下载后都会验证其 hash 是否与线上( 默认:sum.golang.org 国内:sum.golang.google.cn)记录的一致。
- 验证的过程可以通过环境变量 GONOSUMDB 和 GOSUMDB 来控制:首先来看 GOSUMDB 的配置,它指定了需要使用的线上数据库地址。因为默认使用的 sum.golang.org 在国内无法访问,如果配置使用的是 google 搭建的国内镜像,还可以配置为 off,代表禁用校验,即下载模块不进行哈希值的校验,彻底抛弃这个过程。使用中我不建议这样做,可以使用 GONOSUMDB 的环境变量去配置不需要验证的模块,比如私有模块肯定是不能通过验证的。GONOSUMDB 是通过前缀匹配的方式运行的。图中配置了 gitlab.com,那么所有以 gitlab.com 开头的包都不会进行 GO 的校验和检查。
- 验证的过程可以通过环境变量 GONOSUMDB 和 GOSUMDB 来控制:首先来看 GOSUMDB 的配置,它指定了需要使用的线上数据库地址。因为默认使用的 sum.golang.org 在国内无法访问,如果配置使用的是 google 搭建的国内镜像,还可以配置为 off,代表禁用校验,即下载模块不进行哈希值的校验,彻底抛弃这个过程。使用中我不建议这样做,可以使用 GONOSUMDB 的环境变量去配置不需要验证的模块,比如私有模块肯定是不能通过验证的。GONOSUMDB 是通过前缀匹配的方式运行的。图中配置了 gitlab.com,那么所有以 gitlab.com 开头的包都不会进行 GO 的校验和检查。
-
GONOSUMDB
- 用于配置不需要校验的模块。
- 举例子:
go env -w GONOSUMDB=*.example.com,wt.io/private
这样的话,像 “http://git.example.com/xyzzy”, "wt.io/private/test"这些公司和自己的私有仓库就都不会做校验了。
-
GOPRIVATE
- 相当于前面两个环境变量(
GONOPROXY
和GONOSUMDB
)的集合,配置了 GOPRIVATE 就相当于把前面的两个环境变量一起配置了。
- 相当于前面两个环境变量(
2. 我的理解
- 关于
GOPROXY
:- 从字面意思就能看出,GOPROXY表示的是go的代理设置,之所以有这个环境变量,是因为go这种语言不像C语言,在C语言中,如果我们想要使用别人的第三方代码,一般有两种途径:而在go语言中,类似于java,可以在编程时,引入第三方代码的库地址,比如git仓库,然后在编译的时候,IDE会自动的拉取第三方库文件到当前工程。这样做虽然很方便,但是带来了一个问题:网速和限制,golang默认的GOPROXY是https://goproxy.io,这个是官方的设置,我们可以使用国内的代理,Windows下设置如下:,因为一些限制,我们不能很顺利的使用和下载这些仓库,这样就会导致下载缓慢或者失败,所以这个时候就需要一个代理来实现下载,这个代理就是中间商,可以跨过限制来访问。
- GO 支持通过 GOPROXY 协议获取 GO 模块。模块是基于 HTTP 协议的,只会使用 HTTP 的 get 请求,并且使用标准的 HTTP 状态码进行调用。当使用的公共 GOPROXY 协议,其 GOPROXY 代理服务器默认都是没有用户名和密码的。但实际上如果需要搭建私有的,是可以支持 HTTP 基础授权,方式与前面一样,通过 .netrc 文件去配置用户名和密码。另外 GOPROXY 还有两点特性:
- 第一:比起使用 VCS 方式直接去克隆,GOPROXY 获取模块的速度会更快,原因后面会详细说明。
- 第二:可以解决模块不能访问的问题,比如 Golang 域名访问不了等问题,通过第三方搭建好的代理服务器即可访问下载到这些模块。
- GOPROXY 的配置是通过 GOPROXY 环境变量来控制,配置的是代理服务器URL。代理服务器 URL 可以配置多个,通过逗号和管道符来进行分割,管道符和逗号的区别后面会举例讲解。
- 通过固定的字符串 off 和 direct 可以代替 URL。off 禁止从任何来源去下载模块,把 GOPROXY 设置为 off 会禁止下载模块,只能使用本地模块,无论从 gitlab、github或其他地方的模块都不能下载。direct 代表直接从VCS上拉取,一般会作为备选方案。
export GOPROXY='https://proxy.golang.org,direct'
以及go env -w GOPROXY='https://goproxy.cn|direct'
:- 第一个是 Linux 环境变量的语法,通过 export 来设置环境变量。前面配置了proxy.golang.org,这是 google 官方的 goproxy 的服务器,逗号之后指定了备选方案 direct。在 GOPROXY 服务器返回403和410状态码时,表示找不到模块。以逗号为分隔指定备选方案时只有当服务器返回了403或410状态码时,go get 会尝试使用备选方案,这里是从版本管理平台上去下载代码。
- 第二个使用了另一种语法配置,go env -w 语法是 GO 自带的,GO1.13版本开始支持。它是可以跨平台使用的,通过这种语法,没有操作系统的差异,在 windows、Linux、max 上面,都可以通过该方式去配置 GO 相关的环境变量。示例中设置成了国内常用的 proxy 的地址:goproxy.cn。这里使用了管道符指定备选方案,管道符的意义是无论代理服务器返回了什么错误,即便不是 HTTP 的错误,如 GOproxy 服务器挂了返回500的错误,或者网络错误。都会尝试使用备选方案去下载模块。
# 设置镜像 注:其中 -w 表示 写 操作。
go env -w GOPROXY=https://goproxy.cn,direct
二、为什么
解决什么问题,可以带来什么好处?
优点:
- 它可以管理一个依赖库的多个版本同时存在。
缺点:
三、怎么用
1. 应用场景
操作命令说明:
序号 | 命令 | 说明 |
---|---|---|
01 | go mod download | download modules to local cache(下载依赖包) |
02 | go mod edit | edit go.mod from tools or scripts(编辑go.mod) |
03 | go mod graph | print module requirement graph (打印模块依赖图(列表)) |
04 | go mod verify | initialize new module in current directory(在当前目录初始化mod) |
05 | go mod tidy | add missing and remove unused modules(拉取缺少的模块,移除不用的模块) |
06 | go mod vendor | make vendored copy of dependencies(将依赖复制到vendor下) |
07 | go mod verify | verify dependencies have expected content (验证依赖是否正确) |
08 | go mod why | explain why packages or modules are needed(解释为什么需要依赖) |
- go mod init # 初始化当前目录为模块根目录,生成go.mod, go.sum文件。
- go mod download # 下载依赖包。
- go mod tidy #整理检查依赖,如果缺失包会下载或者引用的不需要的包会删除。
- go mod vendor #复制依赖到vendor目录下面。
2. 具体应用
replace
让原本依赖的 github.com/repo/pkg 包,实际使用 github.com/your-fork/pkg@version。
go mod edit -replace github.com/repo/pkg=github.com/your-fork/pkg@version
清缓存
go clean -modcache
go.mod
:依赖列表和版本约束。go.sum
:记录module文件hash值,用于安全校验。
3. 注意事项
- go mod不推荐使用vendor,不要将vendor提交到版本控制。
- 提交go.mod,可以忽略go.sum,因为会根据校验sum跨平台可能报错。
- go mod 维护了两个主要文件 go.sum 和 go.mod:
- go.mod 维护了项目的golang版本以及golang依赖的库。
- go.sum 维护了项目依赖库的版本管理信息,类似 svn/git 的一个库版本记录,可以切换同一个库的不同版本。
4. 实战操作
–方式1:–begin–
第一步:初始化项目
# 随便找一个位置新建一个文件夹study go mod init 包名(模块名)
go mod init 包名
go.mod文件一旦创建后,它的内容将会被go toolchain全面掌控。go toolchain会在各类命令执行时,比如go get、go build、go mod等修改和维护go.mod文件。
-
go.mod 提供了module, require、replace和exclude 四个命令:
- module 语句指定包的名字(路径)。
- require 语句指定的依赖项模块。
- replace 语句可以替换依赖项模块。
- exclude 语句可以忽略依赖项模块。
第二步:添加依赖
package main
import (
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})
r.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}
第三步:引入第三方包
# 第二步中对应的包
go get github.com/gin-gonic/gin
# 查看go.mod文件内容
module study
go 1.16
require github.com/gin-gonic/gin v1.7.4 // indirect
注意:go mod模式引入的第三方包,默认存放在GOPATH下面的pkg目录,注意查看GOPATH。
go module 安装 package 的原則是先拉最新的 release tag,若无tag则拉最新的commit,go 会自动生成一个 go.sum 文件来记录 dependency tree。
可以使用命令 go list -m -u all 来检查可以升级的package,使用go get -u need-upgrade-package 升级后会将新的依赖版本更新到go.mod * 也可以使用 go get -u 升级所有依赖。
-
go get 升级:
- 运行 go get -u 将会升级到最新的次要版本或者修订版本(x.y.z, z是修订版本号, y是次要版本号)。
- 运行 go get -u=patch 将会升级到最新的修订版本。
- 运行 go get package@version 将会升级到指定的版本号version。
- 运行go get如果有版本的更改,那么go.mod文件也会更改
使用replace替换无法直接获取的package:由于某些已知的原因,并不是所有的package都能成功下载,比如:golang.org下的包。
replace (
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a => github.com/golang/crypto v0.0.0-20190313024323-a1f597ede03a
)
–方式1:–end–
–方式2:–begin–【go mod使用】
第一步:初始化项目
# 随便找一个位置新建一个文件夹learn go mod init 包名(模块名)
go mod init learn
第二步:创建一个文件venki.go
package learn
import "fmt"
// say Hi to venki
func SayHi(name string) string {
return fmt.Sprintf("Hi, %s", name)
}
第三步:初始化mod
go mod init gitee.com/venki/go_study_accumulate
# go mod文件内容
module gitee.com/venki/go_study_accumulate
go 1.16
第四步:发布go.mod到仓库,供其他项目使用
git init
# 忽视规则文件
vim .gitignore
git add -A
git commit -m '初始化mod'
# github创建对应的repo
git remote add origin gitee.com/venki/go_study_accumulate.git
git push -u origin master
这个时候没有加tag,所以,没有版本的控制。默认是v0.0.0后面接上时间和commitid。如下:
learn@v0.0.0-20200517004046-ee882713fd1e
第五步:使用tag,进行版本控制
git tag v1.0.0
git push --tags
第六步:维护v1.0.0分支
$git checkout -b v1
$git push -u origin v1
再切出一个分支,用于后续v1.0.0的修复推送,不要直接在master分支修复。
第七步:其他项目使用mod
# 在study项目使用
创建一个main.go文件
package main
import (
"github.com/gin-gonic/gin"
"gitee.com/venki/go_study_accumulate v0.0.0" # 注意此处引入mod
)
func main() {
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})
r.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}
第八步:加载go mod
go mod tidy
–方式2:–end–
四、思考点
1. 它山之石
- 这里面有个坑,就是设置为auto的时候并且在GOPATH/src下,如果该目录或者父目录存在go.mod, go.sum文件,则go mod也是启用的。(go1.13已经默认开启)。
- go mod虽好,但是费开发者的电脑磁盘,
go mod
拉下的包都会放当前目录的pkg/mod目录下面,意味着不同项目引用相同的包会重复下载,不像java的maven本地一个集中的目录,不重复下载。 - 注:
在使用go modules时,GOPATH是无意义的,不过它还是会把下载的依赖存储在$GOPATH/pkg/mod 中
也会把go install 的结果放在 $GOPATH/bin 中。
当modules 功能启用时,依赖包的存放位置变更为$GOPATH/pkg
允许同一个package多个版本并存,且多个项目可以共享缓存的module。