英文:
Random REFUSED_STREAM making a POST multipart form request
问题
这是使用golang将apk文件(几MB)上传到appetize.io的代码:
func uploadToAppetize(file multipart.File, branchName string, displayName string) (result *AppetizeRes, ok bool) {
file.Seek(0, 0)
url, _ := getUrl()
var buffer bytes.Buffer
writer := multipart.NewWriter(&buffer)
fileName := displayName + "/" + branchName
part, err := writer.CreateFormFile("file", fileName)
if err != nil {
fmt.Fprintf(os.Stderr, "Error creating form file %v: %v\n", fileName, err)
return nil, false
}
size, err := io.Copy(part, file)
if err != nil {
fmt.Fprintf(os.Stderr, "Error copying apk file data: %v\n", err)
return nil, false
}
fmt.Fprintf(os.Stdout, "Copied %v bytes for uploading to appetize...\n", size)
writer.Close()
response, err := http.Post(url, writer.FormDataContentType(), &buffer) // Random error on this line
if err != nil || response == nil {
fmt.Fprintf(os.Stderr, "Error occurred uploading apk data to appetize.io: %v %v\n", err, response)
return nil, false
}
defer response.Body.Close()
if response.StatusCode != http.StatusOK {
return nil, false
}
var appetizeRes AppetizeRes
if err := json.NewDecoder(response.Body).Decode(&appetizeRes); err != nil {
return nil, false
}
return &appetizeRes, true
}
然而,我在http.Post(...)这一行遇到了一个随机错误。它返回一个空的响应和一个错误。错误信息是"stream error: stream ID 1; REFUSED_STREAM"。这个错误会随机发生,但在go程序首次发出请求后肯定会发生。
这是go的版本:
go version go1.8.1 darwin/amd64
我还在另一台运行go 1.6.*的Mac上运行了这个程序,我不记得在那台Mac上遇到过这个问题。
有什么想法吗?
英文:
This is the code to upload an apk file (several MB) to appetize.io using golang:
func uploadToAppetize(file multipart.File, branchName string, displayName string) (result *AppetizeRes, ok bool) {
file.Seek(0, 0)
url, _ := getUrl()
var buffer bytes.Buffer
writer := multipart.NewWriter(&buffer)
fileName := displayName + "/" + branchName
part, err := writer.CreateFormFile("file", fileName)
if err != nil {
fmt.Fprintf(os.Stderr, "Error creating form file %v: %v\n", fileName, err)
return nil, false
}
size, err := io.Copy(part, file)
if err != nil {
fmt.Fprintf(os.Stderr, "Error copying apk file data: %v\n", err)
return nil, false
}
fmt.Fprintf(os.Stdout, "Copied %v bytes for uploading to appetize...\n", size)
writer.Close()
response, err := http.Post(url, writer.FormDataContentType(), &buffer) // Random error on this line
if err != nil || response == nil {
fmt.Fprintf(os.Stderr, "Error occurred uploading apk data to appetize.io: %v %v\n", err, response)
return nil, false
}
defer response.Body.Close()
if response.StatusCode != http.StatusOK {
return nil, false
}
var appetizeRes AppetizeRes
if err := json.NewDecoder(response.Body).Decode(&appetizeRes); err != nil {
return nil, false
}
return &appetizeRes, true
}
However I am receiving an random error on the line http.Post(...). It returns a nil response and an error. The error is "stream error: stream ID 1; REFUSED_STREAM". It happens randomly but will surely happen the first time the go program make the request after launching.
This is the go version:
go version go1.8.1 darwin/amd64
This is the response header from the server if it doesn't fail:
I also run this program on another mac running go 1.6.*, I didn't remember I ever run into this issue on that mac.
Any idea what's going on?
答案1
得分: 2
golang标准库net/http
中存在一个bug,无法正确处理REFUSED_STREAM
的http/2错误。可能发生的情况如下:
-
golang客户端打开一个TCP连接到HTTP/2的www服务器,并将连接中的最大HTTP流数量设置为1000,并立即开始上传。
-
HTTP/2的www服务器告诉golang客户端只使用给定数量的流,但是golang客户端已经开始了超过该数量的流。
-
HTTP/2的www服务器对此做出反应,重置多余的流。
-
golang的
net/http
代码中缺乏对重试的正确支持,导致流在被服务器重置后失败,最终上传也失败。
关于这个问题在GitHub上有一个开放的问题:x/net/http2: retry requests rejected with REFUSED_STREAM - golang/go/issues/20985
**这个问题已经在主分支中关闭,修复将包含在未来的Golang版本1.10中。
1: https://github.com/golang/go/issues/20985/ "x/net/http2: retry requests rejected with REFUSED_STREAM"
英文:
There is a bug in the golang standard library net/http
that fails to handle the REFUSED_STREAM
http/2 error properly. This is what is likely going on:
-
golang client opens a TCP connection to the HTTP/2 www server, sets the maximum number of HTTP streams in the connection to 1000 and starts uploading immediately.
-
The HTTP/2 www server tells the golang client to only use a given number of streams, but the golang client has already started more than that amount of streams.
-
The HTTP/2 www server reacts to this by resetting the excess streams.
-
The lack of proper support for a retry in the golang
net/http
code causes the stream to fail after being reset by the server, and eventually the upload fails as well.
There is a ticket open about this issue on github: x/net/http2: retry requests rejected with REFUSED_STREAM - golang/go/issues/20985
**This issue has been closed in the master branch, the fix will be included in future Golang version 1.10
1: https://github.com/golang/go/issues/20985/ "x/net/http2: retry requests rejected with REFUSED_STREAM"
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论