模块代理
GOPROXY
协议
模块代理是一个 HTTP 服务器,可以响应对 GET
下面指定路径的请求。这些请求没有查询参数,也不需要特定的协议头,所以即使是从固定文件系统(包括 file://
URL )提供服务的站点也可以是模块代理。
成功的 HTTP 响应必须有状态代码200(OK)。遵循重定向(3xx)。状态代码为 4xx 和 5xx 的响应被当作错误处理。错误代码404(Not Found)和410(Gone)表示请求的模块或版本在代理上不可用,但可以在其他地方找到。错误响应的内容类型是 text/plain
,charset
是 utf-8
或 us-ascii
。
该 go
命令可以配置使用 GOPROXY
环境变量连接代理或源码服务器,该环境变量接受代理 URL 列表。列表中可以包括关键字 direct
或 off
(有关详细信息,请参阅 Environment variables)。 列表元素可以用逗号(,
)或竖线(|
)隔开,这决定了错误回退行为。当一个 URL 后面有逗号时,go
命令只有在出现404(Not Found)或410(Gone)响应后才会使用到后面的代理源。当一个URL后面有一个竖线时,go
命令在出现任何错误后,包括非 HTTP 错误,如超时,都会返回到后面的代理源。这种错误处理行为让代理成为未知模块的看门人。例如,对于不在批准名单上的模块,代理可以用403错误(Forbidden)响应(请参阅 Private proxy serving private modules)。
下表指定了模块代理必须响应的查询。对于每个路径,$base
是代理URL的路径部分,$module
是一个模块路径,而$version
是一个版本。例如,如果代理URL是https://example.com/mod
,则客户端请求模块 golang.org/x/text
的go.mod
文件在版本v0.3.2
上,客户端将发送GET
请求 https://example.com/mod/golang.org/x/text/@v/v0.3.2.mod
。
为了避免在不区分大小写的文件系统服务时歧义,$module
和$version
通过替换具有感叹号的每一个大写字母,然后相应的下部替换每个大写字母案例信。这允许模块example.com/M
和example.com/m
两者都存储在磁盘上,因为前者被编码为example.com/!m
。
路径 | 描述 |
---|---|
$base/$module/@v/list |
在纯文本中返回给定模块的已知版本的列表,每行。此列表不应包含伪版本。 |
$base/wmodule/@v/wrversion.info |
返回关于模块的特定版本的JSON格式的元数据。响应必须是与下面的Go数据结构对应的JSON对象:键入信息构造体 { Version string // version string Time time.Time // commit time} Version 字段是必需的,必须包含一个有效,规范版(参见版本)。请求路径中的$ Version 不需要是相同的版本甚至有效版本;此端点可用于查找分支名称或修订标识符的版本。但是,如果$version 是一个规范版本,具有与$module 兼容的主要版本,如果成功响应的Version 字段必须相同。Time 字段是可选的。如果存在,则必须是RFC 3339格式中的字符串。它表示创建了版本的时间。可以将来添加字段,因此保留其他名称。 |
$base/wmodule/@v/wrversion.mod |
返回模块的特定版本的go.mod 文件。如果该模块在请求的版本中没有go.mod 文件,则必须返回仅包含带有所请求的模块路径的module 语句的文件。否则,必须返回原始,未修改的go.mod 文件。 |
$base/wmodule/@v/wrversion.zip |
返回包含模块的特定版本内容的zip文件。有关必须格式化的ZIP文件的详细信息,请参见Module zip文件。 |
$base/$module/@latest |
以与$base/wermoders.info 相同的格式返回有关最新已知版本的模块的元数据。最新版本应该是go 命令应该使用的模块版本,如果$base/$module/@v/list 为空或未列出的版本是合适的。此端点是可选的,并且不需要模块代理来实现它。 |
在解析模块的最新版本时,go
命令将请求 $base/$module/@v/list
,然后,如果没有找到合适的版本,$base/$module/@latest
。go
命令更喜欢:语义上最高的发布版本,语义上最高的预发布版本以及按时间顺序最新的伪版本。在Go 1.12及更早版本中,go
命令被认为是伪版本的$base/$module/@v/list
是预发布版本,但这从Go 1.13是不正确的。
模块代理必须始终为同样的内容服务,以便成功响应$base/$module/$version.mod
和$base/$module/$version.zip
查询。此内容是加密认证使用go.sum
文件,默认情况下,校验数据库。
go
命令缓存大多数内容它在$GOPATH/pkg/mod/cache/download
中的模块缓存中的模块代理下载。即使在直接从版本控制系统下载时,go
命令也是显式info
,mod
,zip
文件并将它们存储在其中目录,与它直接从代理下载过的目录。缓存布局与代理URL空间相同,因此服务$GOPATH/pkg/mod/cache/download
在(或将其复制到)https://example.com/proxy
让用户通过将 GOPROXY
设置为https://example.com/proxy
来让用户访问缓存的模块版本。
与代理通信
go
命令可以通过module 代理下载模块源代码和元数据。GOPROXY
环境变量可用于配置go
命令可以连接到的代理和是否它可以直接与版本控制系统进行通信。下载的模块数据保存在module cache中保存。go
命令只会在需要在缓存中的信息时与代理联系。
GOPROXY
协议部分描述了可以发送到GOPROXY
服务器的请求。但是,了解这些在go
命令发起请求时也是有帮助的。例如,go build
以下步骤:
- 通过阅读来计算构建列表
go.mod
文件 和执行最小版本选择(MVS)。 - 阅读命令行中命名的包和他们导入的包。
- 如果Build列表中的任何模块未提供包,请查找提供它的模块。将模块要求添加到
go.mod
上并重新开始。 - 装入一切后,构建包。
当go
命令计算构建列表时,它会加载module 图中的每个模块的go.mod
文件。如果go.mod
文件不在缓存中,则go
命令将使用$module/@v/$version.mod
从代理下载请求(其中$module
是模块路径, $version
是版本)。可以使用像curl
的工具来测试这些请求。例如,下面的命令在版本v0.2.0
时从golang.org/x/mod
下载go.mod
文件:
$ curl https://proxy.golang.org/golang.org/x/mod/@v/v0.2.0.mod
module golang.org/x/mod
go 1.12
require (
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898
)
为了加载包,go
命令需要提供它的模块的源代码。模块源代码分布在.zip
文件中,该文件被提取到模块缓存中。如果模块.zip
不在缓存中,则go
命令将使用$module/@v/$version.zip
请求下载。
$ curl -O https://proxy.golang.org/golang.org/x/mod/@v/v0.2.0.zip
$ unzip -l v0.2.0.zip | head
Archive: v0.2.0.zip
Length Date Time Name
--------- ---------- ----- ----
1479 00-00-1980 00:00 golang.org/x/mod@v0.2.0/LICENSE
1303 00-00-1980 00:00 golang.org/x/mod@v0.2.0/PATENTS
559 00-00-1980 00:00 golang.org/x/mod@v0.2.0/README
21 00-00-1980 00:00 golang.org/x/mod@v0.2.0/codereview.cfg
214 00-00-1980 00:00 golang.org/x/mod@v0.2.0/go.mod
1476 00-00-1980 00:00 golang.org/x/mod@v0.2.0/go.sum
5224 00-00-1980 00:00 golang.org/x/mod@v0.2.0/gosumcheck/main.go
请注意,.mod
和.zip
请求是分开的,即使go.mod
文件通常包含在.zip
文件中。go
命令可能需要下载许多不同模块的go.mod
文件,而.mod
文件远小于.zip
文件。此外,如果Go项目没有go.mod
文件,则代理将为合成的go.mod
文件提供服务,该文件只包含module
指令。 合成的go.mod
文件由go
命令从版本控制系统下载时生成。
如果go
命令需要加载构建列表中任何模块未提供的包,则会尝试找到提供它的新模块。 将package解析为module描述了此过程。总之,go
命令请求有关可能包含包的最新版本的最新版本的信息。例如,对于包golang.org/x/net/html
,go
命令将尝试查找模块golang.org/x/net/html
,golang.org/x/net
,golang.org/x/
,和golang.org
的最新版本。只有golang.org/x/net
实际存在并提供该包,因此go
命令使用该模块的最新版本。如果多个模块提供包,则go
命令将使用具有最长路径的模块。
当go
命令请求最新版本的模块时,它首先向$module/@v/list
发送请求。如果列表为空或无法使用返回的版本,则它会向 $module/@latest
发送请求。选择版本后,go
命令发送$module/@v/$version.info
元数据的请求。然后,它可以发送$module/@v/wrversion.mod
和$module/@v/wrversion.zip
请求加载go.mod
的文件和源代码。
$ curl https://proxy.golang.org/golang.org/x/mod/@v/list
v0.1.0
v0.2.0
$ curl https://proxy.golang.org/golang.org/x/mod/@v/v0.2.0.info
{"Version":"v0.2.0","Time":"2020-01-02T17:33:45Z"}
下载.mod
或.zip
文件后,go
命令计算加密哈希,并检查它与主模块的go.sum
文件中的哈希匹配。如果哈希不存在go.sum
,则默认情况下,go
命令从checksum database检索它校验和数据库。如果计算的散列不匹配,则go
命令报告安全错误,并未在模块缓存中安装文件。 GOPRIVATE
和GONOSUMDB
环境变量可用于禁用对特定模块的校验和数据库的请求。GOSUMDB
环境变量也可以设置为off
以完全禁用对校验和数据库的请求。有关更多信息,请参阅Authenticating modules。请注意,为.info
请求返回的版本列表和版本元数据未经身份验证,并且可能会随时间变化。
直接从代理服务模块
大多数模块都是从版本控制存储库开发和服务。在direct模式中,go
命令用一个版本控制工具下载这样的模块(参见版本控制系统)。也可以直接从模块代理服务模块。这对于想要在不公开其版本控制服务器的情况下提供模块的组织和使用版本控制工具的组织的组织非常有用。go
命令不支持。
当go
命令以直接模式下载模块时,它首先使用基于模块路径的HTTP GET请求查找模块服务器的URL。它寻找一个<meta>
标签,名称go-import
中的HTML 响应。标记的内容必须包含存储库根路径,版本控制系统和由空格分隔的URL。有关详细信息,请参阅查找模块路径的存储库。
如果版本控制系统是mod
,则go
命令使用GOPROXY
协议从给定的URL下载模块。
例如,假设go
命令正在尝试下载modulexample.com/gopher
在版本v1.0.0
上。它向https://example.com/gopher?go-get=1
发送请求。服务器响应包含标记的HTML文档响应:
<meta name="go-import" content="example.com/gopher mod https://modproxy.example.com">
基于此响应,go
命令通过向https://modproxy.example.com/example.com/gopher/@v/v1.0.0.info
,v1.0.0.0.0.0.0mod
,和v1.0.0.zip
发送请求来下载模块。
请注意,直接从代理服务的模块无法使用GOPATH模式下载go get
。
本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
推荐文章: