为了账号安全,请及时绑定邮箱和手机立即绑定

http:阅读已关闭的响应正文 - httptest.NewServer

http:阅读已关闭的响应正文 - httptest.NewServer

Go
阿晨1998 2022-10-17 10:24:43
我正在尝试使用 httptest.NewServer 进行测试,但遇到了障碍。在我的代码中,我正在向外部 API 发出 GET 请求,并且我想使用 httptest.NewServer 对此进行测试。这是我发出请求的代码(main.go):package mainimport (    "fmt"    "io"    "io/ioutil"    "log"    "net/http")type HTTPClient interface {    Do(req *http.Request) (*http.Response, error)}type NewRequest interface {    NewRequest(method string, url string, body io.Reader) (*http.Request, error)}var (    Client HTTPClient)func init() {    Client = &http.Client{}}func main() {    url := "https://httpbin.org/get"    GetData(url)}func GetData(url string) (*http.Response, error) {    req, err := http.NewRequest(http.MethodGet, url, nil)    if err != nil {        log.Fatalln(err)        return nil, err    }    resp, err := Client.Do(req)    if err != nil {        log.Fatalln(err)        return nil, err    }    defer resp.Body.Close()    responseBody, err := ioutil.ReadAll(resp.Body)    if err != nil {        log.Fatal(err)        return nil, err    }    fmt.Println(resp.Status)    fmt.Println(string(responseBody))    return resp, nil}当我运行它时,它工作正常。这是我的测试文件:package mainimport (    "fmt"    "io/ioutil"    "log"    "net/http"    "net/http/httptest"    "testing")func TestYourHTTPGet(t *testing.T){    ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {        fmt.Fprintln(w, `response from the mock server goes here`)    }))    defer ts.Close()    mockServerURL := ts.URL    resp, err := GetData(mockServerURL)    if err != nil {        fmt.Println("Error 1: ", err)    }    defer resp.Body.Close()    responseBody, err := ioutil.ReadAll(resp.Body)    if err != nil {        log.Fatal("Error 2: ", err)    }    fmt.Println(resp.Status)    fmt.Println(string(responseBody))}当我运行时,go test我收到错误:http: read on closed response body。如果我defer resp.Body.Close()从main.go测试中删除正确通过。我不确定为什么会发生这种情况,并希望有人可以解释这里发生了什么?
查看完整描述

2 回答

?
慕斯王

TA贡献1864条经验 获得超2个赞

正如@Cerise Limón 所说,你打resp.Body.Close()了两次电话,然后尝试阅读封闭的身体。要修复您的代码,您可以从GetData函数中删除主体处理并在外部执行GetData或返回主体而不在测试中读取它。


main.go:


package main


import (

    "fmt"

    "io/ioutil"

    "log"

    "net/http"

)


var Client = &http.Client{}


func main() {

    url := "https://httpbin.org/get"


    status, data, err := GetData(url)

    if err != nil {

        log.Fatalln(err)

    }


    fmt.Println(status)

    fmt.Println(string(data))

}


func GetData(url string) (status string, body []byte, err error) {

    req, err := http.NewRequest(http.MethodGet, url, nil)

    if err != nil {

        return

    }


    resp, err := Client.Do(req)

    if err != nil {

        return

    }


    defer resp.Body.Close()


    body, err = ioutil.ReadAll(resp.Body)

    if err != nil {

        log.Fatalln(err)

    }


    return resp.Status, body, nil

}


main_test.go:


package main


import (

    "fmt"

    "net/http"

    "net/http/httptest"

    "testing"

)


func TestYourHTTPGet(t *testing.T){

    ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

        fmt.Fprintln(w, `response from the mock server goes here`)

    }))

    defer ts.Close()


    mockServerURL := ts.URL


    status, data, err := GetData(mockServerURL)

    if err != nil {

        fmt.Println("Error 1: ", err)

    }


    fmt.Println(status)

    fmt.Println(string(data))

}


查看完整回答
反对 回复 2022-10-17
?
蝴蝶不菲

TA贡献1810条经验 获得超4个赞

GetData()的 return 是一个指针。你跑GetData()进去main.go,retun时,它会关闭resp.body。如果你再读一遍,它会导致http: read on closed response body

所以如果你想再次阅读正文,你不应该返回*http.Response,你应该克隆resp.body返回


查看完整回答
反对 回复 2022-10-17
  • 2 回答
  • 0 关注
  • 168 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号