Golang httpClient调用Minio预签名PUT URL返回MissingContentLength错误求助
问题根因
你遇到的报错是Go标准库net/http的实现逻辑和Minio预签名接口的约束共同导致的:
- Go标准库
net/http中,Content-Length由http.Request结构体的ContentLength字段独立控制,手动往Request.Header中设置Content-Length不会生效,发起请求时会被客户端忽略 - 当
ContentLength未显式赋值时,http.Client默认会对os.File类型的请求体使用分块传输编码,而Minio的预签名PUT接口不支持分块传输,因此强制要求请求必须携带Content-Length头 - curl的
--upload-file参数会自动读取文件大小并显式设置Content-Length,因此可以正常上传
解决方案
只需要在原有代码的基础上,把读取到的文件大小赋值给request.ContentLength字段即可,修正后的代码如下:
url := "http://pre-signed-url-to-bucket-obj" fileName := "test.txt" file, err := os.Open(fileName) if err != nil { log.Fatal(err) } defer file.Close() // 读取文件大小 fStat, err := file.Stat() if err != nil { log.Fatal("Error getting file info:", err) } request, err := http.NewRequest(http.MethodPut, url, file) if err != nil { log.Fatal("Error creating request:", err) } // 直接给Request的ContentLength字段赋值,不要往Header里写 request.ContentLength = fStat.Size() client := &http.Client{} resp, err := client.Do(request) if err != nil { log.Fatal("Error performing request:", err) } defer resp.Body.Close() content, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal("Error reading response:", err) } log.Println(string(content))
额外注意事项
- 如果上传的是内存字节流,将
[]byte包装为bytes.Reader传入http.NewRequest,标准库会自动识别可寻址的请求体,自动填充ContentLength字段,不需要手动处理 - 不要使用分块传输的请求体调用Minio预签名PUT接口,服务端会直接拒绝
内容的提问来源于stack exchange,提问作者Cirrith
相关产品推荐
相关产品推荐

