从HTTP响应体中读取Golang的内容

huangapple go评论156阅读模式
英文:

Reading on golang from http responce body

问题

我发送请求到服务器并从其中获取答案。你可以看到我的代码:

// 一些代码
queryUrl, err := url.Parse(someValidStringUrl)
resp, err := client.Get(queryUrl.String())

让我们检查err

if err != nil {
    log.Panic("Responce:", resp, "\nError:", err)
}

之后,我想获取响应的主体。我这样做,但是我得到了一个空的字节切片:

var bytes []byte
n, err := resp.Body.Read(bytes)
if err != nil {
    log.Panic(err)
}
log.Println(n, string(bytes))

输出的示例:

2017/07/13 16:32:36 0

这里我找到了另一种方法:

// 一些代码
queryUrl, err := url.Parse(someValidStringUrl)
resp, err := client.Get(queryUrl.String())
if err != nil {
    log.Panic("Responce:", resp, "\nError:", err)
}
defer resp.Body.Close()

if resp.StatusCode == 200 { // OK
    bodyBytes, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        log.Panic(err)
    }
    log.Println(string(bodyBytes))
}

输出的示例:

<html lang='en'>
<head>
</head>
<body>
<title>Hello world</title>
</body>
</html>

请帮助我。这两个示例之间有什么区别?为什么我的方法不起作用?

英文:

I send request to server and get answer from one. You can see my code:

// Some code
queryUrl, err := url.Parse(someValidStringUrl)
resp, err := client.Get(queryUrl.String())

Let's check err:

if err != nil {
    log.Panic(&quot;Responce:&quot;, resp, &quot;\nError:&quot;, err)
}

After this I want get body of my response. I make it such way but I get empty byte slice:

var bytes []byte
n, err := resp.Body.Read(bytes)
if err != nil {
    log.Panic(err)
}
log.Println(n, string(bytes))

Example of output:

> 2017/07/13 16:32:36 0

Here I found another way:

// Some code
queryUrl, err := url.Parse(someValidStringUrl)
resp, err := client.Get(queryUrl.String())
if err != nil {
    log.Panic(&quot;Responce:&quot;, resp, &quot;\nError:&quot;, err)
}
defer resp.Body.Close()

if resp.StatusCode == 200 { // OK
    bodyBytes, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Panic(err)
	}
    log.Println(string(bodyBytes))
}

Example of output:

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-html -->

&lt;html lang=&#39;en&#39;&gt;
&lt;head&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;title&gt;Hello world&lt;/title&gt;
&lt;/body&gt;
&lt;/html&gt;

<!-- end snippet -->

Please, help me. What differences between such examples? Why do my way not work?

答案1

得分: 1

从Golang的Reader文档中可以看到:

Read方法将最多len(p)个字节读入p中。它返回读取的字节数(0 <= n <= len(p))和遇到的任何错误。即使Read返回的n < len(p),在调用期间它也可能使用p的所有空间作为临时空间。如果有一些数据可用但不足len(p)个字节,Read通常会返回可用的数据,而不是等待更多数据。

当Read在成功读取n > 0个字节后遇到错误或文件结束条件时,它返回读取的字节数。它可能返回相同调用中的(非nil)错误,也可能返回后续调用中的错误(以及n == 0)。这种一般情况的一个实例是,返回一个非零字节数的Reader在输入流的末尾可能返回err == EOF或err == nil。下一次Read应该返回0和EOF。

// Reader接口从包文档中显示'p'是输入字节切片。
type Reader interface {
    Read(p []byte) (n int, err error)
}

由于您从未初始化切片,len(bytes)始终为0,因此它只读取0个字节。如果要手动执行您尝试的操作,您需要将切片初始化为非空,并多次调用read,直到最终返回0和EOF,同时将字节追加到某个维护的缓冲区中。这就是为什么希望使用ioutil.ReadAll,它确保正确读取所有内容,您不必担心处理这个问题。

还请注意示例中的defer resp.Body.Close()。在使用读取器和写入器后,始终记得关闭它们是很重要的。

英文:

From Golang's Reader documentation

> Read reads up to len(p) bytes into p. It returns the number of bytes read (0 <= n <= len(p)) and any error encountered. Even if Read returns n < len(p), it may use all of p as scratch space during the call. If some data is available but not len(p) bytes, Read conventionally returns what is available instead of waiting for more.
>
>When Read encounters an error or end-of-file condition after successfully reading n > 0 bytes, it returns the number of bytes read. It may return the (non-nil) error from the same call or return the error (and n == 0) from a subsequent call. An instance of this general case is that a Reader returning a non-zero number of bytes at the end of the input stream may return either err == EOF or err == nil. The next Read should return 0, EOF.

//Reader interface from package documentation showing &#39;p&#39; is the input byte slice.
type Reader interface {
    Read(p []byte) (n int, err error)
}

Since you are never initializing your slice, len(bytes) is always 0 so it only reads 0 bytes. To do it manually like you are trying to do, you would have to initialize the slice to be non-empty and then call read multiple times until it finally returns 0 and EOF while appending bytes to some buffer that you maintain. That is why ioutil.ReadAll is desired, it guarantees that everything is read correctly and you don't have to worry about handling that.

Also note defer resp.Body.Close() in the example. It is important to always remember to close Readers and Writers after using them.

答案2

得分: -1

响应体是一个 Reader。根据文档:

Read 将最多 len(p) 个字节读入 p。它返回读取的字节数(0 <= n <= len(p))和遇到的任何错误。即使 Read 返回的 n < len(p),在调用期间它也可能使用 p 的全部作为临时空间。如果有一些数据可用但不足 len(p) 字节,Read 通常会返回可用的数据,而不是等待更多数据。

由于在将其传递给 Read 时,你的字节切片 var bytes []byte 的长度为 0,它永远不会返回任何字节。

你可以将 []byte 初始化为与返回内容相同的大小:

bytes := make([]byte, resp.ContentLength)

或者,只需使用 ioutil.ReadAll。

英文:

The response body is a Reader. According to the docs:

> Read reads up to len(p) bytes into p. It returns the number of bytes
> read (0 <= n <= len(p)) and any error encountered. Even if Read
> returns n < len(p), it may use all of p as scratch space during the
> call. If some data is available but not len(p) bytes, Read
> conventionally returns what is available instead of waiting for more.

Since the length of your byte slice var bytes []byte is 0 when you pass it into Read, it's never going to return you any bytes.

What you could do is to initialize your []byte to being the same size as the content returned:

bytes := make([]byte, resp.ContentLength)

Or, just use ioutil.ReadAll.

huangapple
  • 本文由 发表于 2017年7月13日 21:42:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/45082449.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定