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 微信会员卡接入微信支付商户号收款
  • ¥15 如何获取烟草零售终端数据
  • ¥15 数学建模招标中位数问题
  • ¥15 phython路径名过长报错 不知道什么问题
  • ¥15 深度学习中模型转换该怎么实现
  • ¥15 HLs设计手写数字识别程序编译通不过
  • ¥15 Stata外部命令安装问题求帮助!
  • ¥15 从键盘随机输入A-H中的一串字符串,用七段数码管方法进行绘制。提交代码及运行截图。
  • ¥15 TYPCE母转母,插入认方向
  • ¥15 如何用python向钉钉机器人发送可以放大的图片?