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

如何在读取响应正文时强制出错

如何在读取响应正文时强制出错

Go
不负相思意 2023-05-08 14:37:44
我已经在 go 中编写了 http 客户端包装器,我需要对其进行彻底测试。我正在使用包装器中的 ioutil.ReadAll 读取响应主体。我在弄清楚如何在 httptest 的帮助下强制从响应主体读取失败时遇到了一些麻烦。package reqfunc GetContent(url string) ([]byte, error) {    response, err := httpClient.Get(url)    // some header validation goes here    body, err := ioutil.ReadAll(response.Body)    defer response.Body.Close()    if err != nil {        errStr := fmt.Sprintf("Unable to read from body %s", err)        return nil, errors.New(errStr)    }    return body, nil}我假设我可以这样设置一个假服务器:package req_testfunc Test_GetContent_RequestBodyReadError(t *testing.T) {    handler := func(w http.ResponseWriter, r *http.Request) {        w.WriteHeader(http.StatusOK)    }    ts := httptest.NewServer(http.HandlerFunc(handler))    defer ts.Close()    _, err := GetContent(ts.URL)    if err != nil {        t.Log("Body read failed as expected.")    } else {        t.Fatalf("Method did not fail as expected")    }}我假设我需要修改 ResposeWriter。现在,我有什么办法可以修改 responseWriter 从而强制包装器中的 ioutil.ReadAll 失败吗?我意识到您似乎认为它是这篇文章的副本,虽然您可能会这样认为或可能是,但仅将其标记为重复并不能真正帮助我。在这种情况下,“重复”帖子中答案中提供的代码对我来说意义不大。
查看完整描述

2 回答

?
元芳怎么了

TA贡献1798条经验 获得超7个赞

检查 的文档Response.Body以查看何时从中读取可能会返回错误:

// Body represents the response body.

//

// The response body is streamed on demand as the Body field

// is read. If the network connection fails or the server

// terminates the response, Body.Read calls return an error.

//

// The http Client and Transport guarantee that Body is always

// non-nil, even on responses without a body or responses with

// a zero-length body. It is the caller's responsibility to

// close Body. The default HTTP client's Transport may not

// reuse HTTP/1.x "keep-alive" TCP connections if the Body is

// not read to completion and closed.

//

// The Body is automatically dechunked if the server replied

// with a "chunked" Transfer-Encoding.

Body io.ReadCloser

最简单的方法是从测试处理程序生成无效的 HTTP 响应。


怎么做?方法有很多种,一个简单的就是“骗”内容长度:


handler := func(w http.ResponseWriter, r *http.Request) {

    w.Header().Set("Content-Length", "1")

}

这个处理程序告诉它有 1 个字节的主体,但实际上它没有发送任何内容。因此在另一端(客户端)尝试从中读取 1 个字节时,显然不会成功,并将导致以下错误:

Unable to read from body unexpected EOF



查看完整回答
反对 回复 2023-05-08
?
慕后森

TA贡献1802条经验 获得超5个赞

要扩展 icza 的精彩答案,您还可以使用httptest.Server对象执行此操作:


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

  w.Header().Set("Content-Length", "1")

}))


defer bodyErrorServer.Close()

然后你可以bodyErrorServer.URL像往常一样通过你的测试,你总是会得到一个 EOF 错误:


package main


import (

    "bytes"

    "fmt"

    "io/ioutil"

    "net/http"

    "net/http/httptest"

    "testing"

    "time"

)


func getBodyFromURL(service string, clientTimeout int) (string, error) {


    var netClient = &http.Client{

        Timeout: time.Duration(clientTimeout) * time.Millisecond,

    }


    rsp, err := netClient.Get(service)

    if err != nil {

        return "", err

    }


    defer rsp.Body.Close()


    if rsp.StatusCode != 200 {

        return "", fmt.Errorf("HTTP request error. Response code: %d", rsp.StatusCode)

    }


    buf, err := ioutil.ReadAll(rsp.Body)

    if err != nil {

        return "", err

    }


    return string(bytes.TrimSpace(buf)), nil

}


func TestBodyError(t *testing.T) {


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

        w.Header().Set("Content-Length", "1")

    }))


    _, err := getBodyFromURL(bodyErrorServer.URL, 1000)


    if err.Error() != "unexpected EOF" {

        t.Error("GOT AN ERROR")

    } else if err == nil {

            t.Error("GOT NO ERROR, THATS WRONG!")

    } else {

        t.Log("Got an unexpected EOF as expected, horray!")

    }

}


此处的游乐场示例:https ://play.golang.org/p/JzPmatibgZn


查看完整回答
反对 回复 2023-05-08
  • 2 回答
  • 0 关注
  • 110 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信