如何从 http.Request 的响应中读取文件内容

How to read file content from an http.Request's response

我使用下面的代码向 HTTP 服务器发送请求。

服务器发送的响应包含那些 http headers

Content-Disposition:[attachment;filename=somefilename.csv] 
Content-Type:[text/csv; charset=UTF-8]

我如何继续检索响应所附文件的内容?

baseUrl := "Some url that i call to fetch csv file"

client := http.Client{}

resp, _ := client.Get(baseUrl)
defer resp.Body.Close()

fmt.Println(resp)

// &{200 OK 200 HTTP/2.0 2 0 map[Content-Disposition:[attachment;filename=somefilename.csv] Content-Type:[text/csv; charset=UTF-8] Date:[Mon, 30 Sep 2019 09:54:08 GMT] Server:[Jetty(9.2.z-SNAPSHOT)] Vary:[Accept]] {0xc000530280} -1 [] false false map[] 0xc000156200 0xc0000c26e0}

您必须使用请求的正文。

baseUrl := "Some url that i call to fetch csv file"

client := http.Client{}

resp, _ := client.Get(baseUrl)
defer resp.Body.Close()
io.Copy(os.Stdout, resp.Body) // this line.

fmt.Println(resp)

如果您必须处理多部分表单数据https://golang.org/pkg/net/http/#Request.FormFile

鉴于以下评论,

i see now after printing resp that there is a csv text but type is http.Response i have to deal with golang.org/pkg/encoding/csv/#Reader how to turn resp to string in order to be able reader to read it, or i miss something else ?

OP 必须理解 http 响应 Body 实现了 io.Reader 接口。 当 http 响应从服务器返回时,正文不会作为字节片 []byte.

直接读入内存

OP 还应注意,csv.Reader 是一种解码使用 io.Reader 的 CSV 编码内容的实现。在引擎盖下它不会将文件的全部内容保存在内存中,它会读取解码一行所需的内容并继续进行。

由于 golang 实现的这两个重要特性,将响应主体 reader 连接到 csv reader.

是简单自然的

对于这个问题,什么是 io.Reader,OP 必须弄清楚它是任何能够通过 max len p 的块读取字节流的东西。这个接口的唯一方法的签名说明了这一点 Read([]byte) (int, error)

此接口的设计方式可最大限度地减少消耗的内存和分配。

引用链接

说了那么多,最后的代码写得很简单,

package main

import (
    "encoding/csv"
    "fmt"
    "io"
    "log"
    "net/http"
)

func main() {
    baseUrl := "https://geolite.maxmind.com/download/geoip/misc/region_codes.csv"

    client := http.Client{}

    resp, err := client.Get(baseUrl)
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()
    fmt.Println(resp)

    r := csv.NewReader(resp.Body)

    for {
        record, err := r.Read()
        if err == io.EOF {
            break
        }
        if err != nil {
            log.Fatal(err)
        }

        fmt.Println(record)
    }
}

最简单的方法就是用ioutil.ReadAll的方法来读全文。 body 实现了 io.Reader 接口,所以你可以用 reader 做的所有事情都可以用 body 完成。这包括将其通过管道传输到标准输出,如 mh-cbon 在他的回答中所示。

baseUrl := "Some url that i call to fetch csv file"

resp, err := http.Get(baseUrl)
if err != nil {
    // do something with the error
}
defer resp.Body.Close()

content, err := ioutil.ReadAll(resp.Body)
if err != nil {
    // do something with the error
}

fmt.Println(string(content))

请注意,我删除了 client。简单的 GET 调用不需要它。如果您需要更多配置,请像示例中那样使用 http.Client

另请注意,content[]byte 类型,但它可以很容易地转换为字符串,如上面在 print 语句中所做的那样。