dtr32221 2016-03-19 23:18
浏览 420
已采纳

在Go中传递响应正文(response.Body)的有效方法是什么?

If I have some code, like the example below, that fetches an image from a link and then saves it to disk, what is the best way to pass around the image data?

I thought about using ioutil.ReadAll(res.Body) to convert it to []byte but passing that around seems expensive, although I can't tell from the documentation whether or not it returns a slice or an array. I also tried returning a pointer to res.Body, a *io.ReadCloser type, but I couldn't figure out how to properly call the .Close() method on the pointed to interface.

I understand that moving the save code into the FetchImage function would probably be the easiest way to solve this but I would like to have these pieces separate if possible.

type ImageData struct {
    Data      io.ReadCloser
    Name      string
}

func FetchImage(url string) (io.ReadCloser, error) {
    res, err := http.Get(url)
    if err != nil {
        return nil, err
    }
    return res.Body, nil
}

func Save(data *ImageData) error {
    defer data.Data.Close()
    file, err := os.Create(data.Name)
    defer file.Close()
    if err != nil {
        return err
    }
    _, err = io.Copy(file, data.Data)
    if err != nil {
        return err
    }
    return nil
}

func main() {
    body, err := fetcher.FetchImage("https://imgur.com/asdf.jpg")
    if err != nil {
        panic(err)
    }
    imageData := ImageData{body, "asdf.jpg"}
    saver := Saver{config.BaseDir, 1}
    err = saver.Save(&imageData)
    if err != nil {
        panic(err)
    }
}

Additionally, I am very new to Go so if there's anything in this code that looks bad please let me know.

  • 写回答

2条回答 默认 最新

  • dty5753 2016-03-19 23:30
    关注

    Use ioutil.ReadAll. The function returns a slice of bytes.

    Slices are efficient to pass around. A slice is a pointer to the backing array, a length and a capacity.

    type ImageData struct {
        Data      []byte
        Name      string
    }
    
    func FetchImage(url string) ([]byte, error) {
        res, err := http.Get(url)
        if err != nil {
            return nil, err
        }
        defer resp.Body.Close()
        if res.StatusCode != 200 {
            return nil, fmt.Errorf("%s: %d", url, res.StatusCode)
        }
        return ioutil.ReadAll(resp.Body)
    }
    
    func Save(data *ImageData) error {
        file, err := os.Create(data.Name)
        if err != nil {
            return err
        }
        defer file.Close()
        _, err := file.Write(data.Data)
        return err
    }
    

    You can also pass around the response body, but use caution. The response body must be closed to release the underlying connection. The code in the question does close the response body, but it's difficult to see because the response body is passed down the function where it's closed.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 HFSS 中的 H 场图与 MATLAB 中绘制的 B1 场 部分对应不上
  • ¥15 如何在scanpy上做差异基因和通路富集?
  • ¥20 关于#硬件工程#的问题,请各位专家解答!
  • ¥15 关于#matlab#的问题:期望的系统闭环传递函数为G(s)=wn^2/s^2+2¢wn+wn^2阻尼系数¢=0.707,使系统具有较小的超调量
  • ¥15 FLUENT如何实现在堆积颗粒的上表面加载高斯热源
  • ¥30 截图中的mathematics程序转换成matlab
  • ¥15 动力学代码报错,维度不匹配
  • ¥15 Power query添加列问题
  • ¥50 Kubernetes&Fission&Eleasticsearch
  • ¥15 報錯:Person is not mapped,如何解決?