模块代理

未匹配的标注

GOPROXY 协议

模块代理是一个 HTTP 服务器,可以响应对 GET 下面指定路径的请求。这些请求没有查询参数,也不需要特定的协议头,所以即使是从固定文件系统(包括 file:// URL )提供服务的站点也可以是模块代理。

成功的 HTTP 响应必须有状态代码200(OK)。遵循重定向(3xx)。状态代码为 4xx 和 5xx 的响应被当作错误处理。错误代码404(Not Found)和410(Gone)表示请求的模块或版本在代理上不可用,但可以在其他地方找到。错误响应的内容类型是 text/plaincharsetutf-8us-ascii

go 命令可以配置使用 GOPROXY 环境变量连接代理或源码服务器,该环境变量接受代理 URL 列表。列表中可以包括关键字 directoff(有关详细信息,请参阅 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/Mexample.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/@latestgo命令更喜欢:语义上最高的发布版本,语义上最高的预发布版本以及按时间顺序最新的伪版本。在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命令也是显式infomodzip文件并将它们存储在其中目录,与它直接从代理下载过的目录。缓存布局与代理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/htmlgo命令将尝试查找模块golang.org/x/net/htmlgolang.org/x/netgolang.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命令报告安全错误,并未在模块缓存中安装文件。 GOPRIVATEGONOSUMDB环境变量可用于禁用对特定模块的校验和数据库的请求。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.infov1.0.0.0.0.0.0mod,和v1.0.0.zip发送请求来下载模块。

请注意,直接从代理服务的模块无法使用GOPATH模式下载go get

本文章首发在 LearnKu.com 网站上。

本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://learnku.com/docs/go-mod/1.17/mod...

译文地址:https://learnku.com/docs/go-mod/1.17/mod...

上一篇 下一篇
贡献者:3
讨论数量: 0
发起讨论 只看当前版本


暂无话题~