golang处理http response碰到的问题和需要注意的点

在处理http response的时候,偶然发现,body读取之后想再次读取的时候,发现读不到任何东西。见下方代码:

response, err = ioutil.ReadAll(resp.Body)
    if err != nil {
        log.Println("ioutil ReadAll failed :", err.Error())
        return
    }

之后如果想再次ioutil.ReadAll(resp.Body)的时候会发现读到的是空。于是我决定去看一下这个resp.Body,发现它是一个io.ReadCloser接口,包含了ReaderCloser接口:

type ReadCloser interface {
    Reader
    Closer
}

于是我想到了文件,它也实现了io.Reader接口,所以用读文件试了下:

func readFile(path string)string{
    fi,err := os.Open(path)
    if err != nil{panic(err)}
    defer fi.Close()

    byte1,err := ioutil.ReadAll(fi)
    fmt.Println(string(byte1))

    byte2,err := ioutil.ReadAll(fi)
    fmt.Println(string(byte2))

    return string(fd)
}

发现结果是一致的,fmt.Println(string(fd2))打印不出任何结果。我猜测应该是ioutil.ReadAll()是有记录偏移量,所以会出现第二次读取读不到的情况。作为client端处理response的时候会碰到这个问题,作为server端要处理request body的时候,一样会遇到此问题,那么该如何解决这个问题呢?
有一个方法是再造一个io.ReadCloser,如下:

    fi2:= ioutil.NopCloser(bytes.NewBuffer(byte1))
    byte3,err := ioutil.ReadAll(fi2)
    fmt.Println(string(byte3))

此外,作为client端处理response的时候,有一点要注意的是,body一定要close,否则会造成GC回收不到,继而产生内存泄露。其实在go的官方源码注释中,也明确注明了response body需要调用方进行手动关闭:It is the caller's responsibility to close Body.

至于response body为什么需要进行关闭,这篇文章进行了解释:
https://studygolang.com/articles/9887

那么作为client端生成的request body,需不需要手动关闭呢,答案是不需要的,net/http中的func (c *Client) Do(req *Request) (*Response, error)会调用Close()

同样的,作为server端接收的request body,也是需要关闭,由Server自动进行关闭,The Server will close the request body. The ServeHTTP Handler does not need to.

你可能感兴趣的:(golang,http)