golang http请求连续多次请求导致EOF错误

新手上路,请多包涵

我正在尝试调试我为我编写的一个简单 REST 库收到的一个非常不寻常的错误。

我正在使用标准的 net/http 包来发出 Get、Post、Put、Delete 请求,但是当我连续发出多个请求时,我的测试偶尔会失败。我的测试看起来像这样:

 func TestGetObject(t *testing.T) {
    firebaseRoot := New(firebase_url)
    body, err := firebaseRoot.Get("1")
    if err != nil {
        t.Errorf("Error: %s", err)
    }
    t.Logf("%q", body)
}

func TestPushObject(t *testing.T) {
    firebaseRoot := New(firebase_url)
    msg := Message{"testing", "1..2..3"}
    body, err := firebaseRoot.Push("/", msg)
    if err != nil {
        t.Errorf("Error: %s", err)
    }
    t.Logf("%q", body)
}

我正在提出这样的要求:

 // Send HTTP Request, return data
func (f *firebaseRoot) SendRequest(method string, path string, body io.Reader) ([]byte, error) {
url := f.BuildURL(path)

// create a request
req, err := http.NewRequest(method, url, body)
if err != nil {
    return nil, err
}

// send JSON to firebase
resp, err := http.DefaultClient.Do(req)
if err != nil {
    return nil, err
}

if resp.StatusCode != http.StatusOK {
    return nil, fmt.Errorf("Bad HTTP Response: %v", resp.Status)
}

defer resp.Body.Close()
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
    return nil, err
}

return b, nil
}

有时它有效,但大多数时候我会遇到 1 或 2 次失败:

 --- FAIL: TestGetObject (0.00 seconds)
firebase_test.go:53: Error: Get https://go-firebase-test.firebaseio.com/1.json: EOF
firebase_test.go:55: ""

--- FAIL: TestPushObject (0.00 seconds)
firebase_test.go:63: Error: Post https://go-firebase-test.firebaseio.com/.json: EOF
firebase_test.go:65: ""
FAIL
exit status 1
FAIL    github.com/chourobin/go.firebase    3.422s

当我提出超过 1 个请求时,就会发生失败。如果我注释掉除 PUT 请求之外的所有内容,测试将始终通过。一旦我包含第二个测试,例如 GET,一个或另一个失败(有时两个都通过)。

原文由 chourobin 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 6k
2 个回答

我猜你的代码没有问题。您的问题最可能的原因是因为服务器正在关闭连接。速率限制是一个可能的原因。

您的测试不应该依赖于非常脆弱且不密封的外部服务。相反,您应该考虑在本地启动测试服务器。

原文由 Jeremy Wall 发布,翻译遵循 CC BY-SA 3.0 许可协议

我可靠地体验了这一点。您需要将 Req.Close 设置为 true(示例中使用的 resp.Body.Close() 语法上的延迟是不够的)。像这样:

 client := &http.Client{}
req, err := http.NewRequest(method, url, httpBody)

// NOTE this !!
req.Close = true

req.Header.Set("Content-Type", "application/json")
req.SetBasicAuth("user", "pass")
resp, err := client.Do(req)
if err != nil {
    // whatever
}
defer resp.Body.Close()

response, err = ioutil.ReadAll(resp.Body)
if err != nil {
    // Whatever
}

原文由 Alex Davies 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题