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

时间:2019-09-30 10:03:33

标签: go multipart content-disposition

我使用下面的代码将请求发送到http服务器。

服务器发送包含这些http标头的响应

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}

2 个答案:

答案 0 :(得分:2)

您必须消耗请求的正文。

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

给出以下评论,

  

我现在在打印resp后看到有一个csv文本,但类型是   http.Response我必须处理golang.org/pkg/encoding/csv/#Reader   如何将resp转换为字符串以便读者能够阅读它,或者我   想念其他东西吗?

OP必须了解http响应主体实现了io.Reader接口。 当http响应从服务器返回时,主体不会作为字节片[]byte直接读入内存。

OP还应注意,csv.Reader是一种对消耗io.Reader的CSV编码内容进行解码的实现。在后台,它没有将文件的全部内容保存在内存中,而是读取解码一行并进一步进行操作所需的内容。

由于golang实现的这两个重要属性,是将响应主体阅读器连接到csv阅读器很容易并且很自然。

对于这个问题,io.Reader是什么,OP必须弄清楚它是能够以最大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)
    }
}

答案 1 :(得分:1)

最简单的方法是使用ioutil.ReadAll方法读取整个正文。该主体实现了io.Reader接口,因此您可以使用该主体完成所有您可以使用阅读器执行的操作。如mh-cbon在他的答案中所示,这包括将其输送到stdout。

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语句中一样轻松地将其转换为字符串。