随机的REFUSED_STREAM导致了一个POST多部分表单请求。

huangapple go评论108阅读模式
英文:

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

如果没有出错,这是服务器的响应头:
随机的REFUSED_STREAM导致了一个POST多部分表单请求。

我还在另一台运行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:
随机的REFUSED_STREAM导致了一个POST多部分表单请求。

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错误。可能发生的情况如下:

  1. golang客户端打开一个TCP连接到HTTP/2的www服务器,并将连接中的最大HTTP流数量设置为1000,并立即开始上传。

  2. HTTP/2的www服务器告诉golang客户端只使用给定数量的流,但是golang客户端已经开始了超过该数量的流。

  3. HTTP/2的www服务器对此做出反应,重置多余的流。

  4. 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:

  1. 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.

  2. 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.

  3. The HTTP/2 www server reacts to this by resetting the excess streams.

  4. 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"

huangapple
  • 本文由 发表于 2017年5月21日 01:50:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/44089111.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定