我在我的应用程序上使用这个 Go API 客户端 https://github.com/heroku/docker-registry-client使用 Go 与 docker registry 交互。这种情况是在使用包“net/http”进行 PUT 请求时在内部遇到一些问题。
当我运行以下代码时,出现错误 Put url: http: ContentLength=2821 with Body length 0
。所以看起来 net/http Client.Do() 函数没有得到我在函数的某个点设置的主体。但是正如您在下面的代码中看到的那样,我仍然有我想要在 []byte
中发送的 JSON 内容。
body, err := manifest.MarshalJSON()
if err != nil {
return err
}
log.Println(string(body)) // I get the JSON data back here
req, err := http.NewRequest("PUT", url, bytes.NewReader(body))
if err != nil {
return err
}
req.Header.Set("Content-Type", manifestV2.MediaTypeManifest)
resp, err := registry.Client.Do(req)
if resp != nil {
defer resp.Body.Close()
}
return err
据我深入研究,错误来自 net/http Client.do()
函数(golang.org/src/net/http/client.go 第 514 行) ,我会说错误是由 Request.GetBody()
函数触发的(来自客户端的第 591 行)。
所以仍然试图更深入地做一些测试来找出这里发生了什么。
有什么线索吗?
如果错误是由服务器给出的,我必须得到这样的东西,但在响应主体中并且在 net/http Client.Do()
调用上没有错误。
Content-Length: <length>
Content-Type: application/json; charset=utf-8
{
"errors:" [
{
"code": <error code>,
"message": "<error message>",
"detail": ...
},
...
]
}
非常感谢!
干杯
最佳答案
问题在 https://github.com/heroku/docker-registry-client 中修改 RoundTripper在获取身份验证 token 后对注册表进行重定向调用。当它尝试将调用重定向到注册表时,正文为空,因为 http.request 正文是一个缓冲区,一旦在第一次调用中读取,缓冲区变为空并且没有正文内容发送重定向调用。
修复它:
if req.Method == "PUT" || req.Method == "POST" {
if req.Body != nil {
reUseBody, _ = req.GetBody()
}
}
在https://github.com/heroku/docker-registry-client/blob/master/registry/tokentransport.go#L17中添加这个和
if req.Method == "PUT" || req.Method == "POST" {
if reUseBody != nil {
req.Body = reUseBody
}
}
在这里https://github.com/heroku/docker-registry-client/blob/master/registry/tokentransport.go#L72
并更改此函数签名 https://github.com/heroku/docker-registry-client/blob/master/registry/tokentransport.go#L71 接受额外的参数。
func (t *TokenTransport) retry(req *http.Request, token string, reUseBody io.ReadCloser)
关于json - 使用 net/http 在 PUT "Body length 0"上出现错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52429036/