Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/go/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Http ioutil.ReadAll(response.Body)永久块-Golang_Http_Go - Fatal编程技术网

Http ioutil.ReadAll(response.Body)永久块-Golang

Http ioutil.ReadAll(response.Body)永久块-Golang,http,go,Http,Go,上面是我的代码,用于从驻留在循环中的网页中读取内容。我发现有时行ioutil.ReadAll(response.Body)会永远阻塞。这是随机发生的,但几乎总是发生在这个网页上:http://xkcd.com/55。非常有趣的是,当我做curl时http://xkcd.com/55,它不返回任何内容,但是,wgethttp://xkcd.com/55返回整个网页。您的代码应按预期工作。我猜,这是一个网络问题。尝试设置更高的超时 tr := &http.Transport{ TLS

上面是我的代码,用于从驻留在循环中的网页中读取内容。我发现有时行
ioutil.ReadAll(response.Body)
会永远阻塞。这是随机发生的,但几乎总是发生在这个网页上:
http://xkcd.com/55
。非常有趣的是,当我做
curl时http://xkcd.com/55
,它不返回任何内容,但是,
wgethttp://xkcd.com/55
返回整个网页。

您的代码应按预期工作。我猜,这是一个网络问题。尝试设置更高的超时

tr := &http.Transport{
    TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
client := &http.Client{Transport: tr}
response, err := client.Get(link)
if err != nil {
    fmt.Println(err)
}
defer response.Body.Close()

//block forever at the next line
content, _ = ioutil.ReadAll(response.Body)

我怀疑您的问题在于,即使出现错误,您也会尝试读取响应正文:

package main

import (
    "crypto/tls"
    "fmt"
    "io/ioutil"
    "net/http"
)

func main() {

    link := "http://xkcd.com/55"

    tr := &http.Transport{
        TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
    }
    client := &http.Client{Transport: tr}
    response, err := client.Get(link)
    if err != nil {
        fmt.Println(err)
    }
    defer response.Body.Close()

    //block forever at the next line
    content, _ := ioutil.ReadAll(response.Body)

    fmt.Println(string(content))

}
在此之后,您应该有一个
else
,或者您应该
return
continue
或其他内容。您的
ReadAll()
行是未定义的行为

(如果您最初是从
Get()
示例代码复制的,请注意,它在错误段中包含了一个
log.Fatalf()
,该错误段将终止程序。)

我怀疑,正如你所说,偶尔你会因为这样或那样的原因出现网络错误。您是否正在检查
Println()
的输出结果?你这样做的话,我可以想象它很容易被隐藏在输出中

作为@twoonotes,这个URL返回一个重定向到同一个URL并带有一个尾随斜杠
Get()
将自动为您处理此问题,因此这不是问题所在。默认情况下,curl不遵循重定向,而wget遵循重定向。您可以通过将
-i
传递给curl来查看标题信息


其他需要核实的事项:

  • 确保您的
    延迟
    确实被调用。请记住,
    defer
    是在函数末尾调用的,而不是在当前范围的末尾调用的。因此,如果您处于循环中(正如您所提到的),您只会累积
    defer
    块,而不会真正关闭这些响应

  • 如果服务器实际上从未关闭连接,则
    io.ReadAll()
    将永远不会返回。这是一个特点。如果你想要一个超时,你需要。您应该能够使用
    curl
    等工具来检验这一假设。有关某些解决方案,请参阅:

    • http.Transport.ResponseHeaderTimeout

我可能已经找到了解决方案,在`&http.Transport中添加了
DisableKeepAlives:true,
,如下所示:

if err != nil {
    fmt.Println(err)
}

自从我做了这个更改,我还没有遇到任何长阻塞。但我不是100%确定这是解决方案。我会让新代码运行一两天。如果没有阻塞,我想这个问题已经解决了。

此外,避免在没有内存/缓冲区限制控制的ReadAll中读取响应体,例如:

tr := &http.Transport{
    TLSClientConfig:   &tls.Config{InsecureSkipVerify: true},
    DisableKeepAlives: true,
}
在好的博客文章中阅读更多关于它的信息:



也许它们是重定向的:请查看我的下载功能以了解这些内容,并附带一个JarCookie:我刚刚测试了下载,它工作正常(使用我的http代码版本)。谢谢@VonC,我将尝试一下。您可能应该为下载添加一个超时,这样,如果服务器确实运行缓慢,您就不会被卡住,问题不在你的代码中。Re:VonC的评论,请注意,重定向到带有斜杠,因此如果此代码不适用于重定向(我实际上不知道),是的,你会在这里被套住。谢谢@Rob,是的,这是一个很好的观点。我放了很多日志,发现这里没有发生错误。然而,它确实在ioutil.ReadAll(response.Body)上被阻塞了。有趣的是,它从不在第一次请求时阻塞。它几乎总是在第二次或第三次请求时阻塞。当服务器在短时间内检测到多个请求时,服务器处理第二个或第三个传入连接的方式与处理第一个不同。我完全理解服务器可能会使用一些策略来防止欺诈。但是我希望它不会永远阻塞。到目前为止它还没有阻塞。然而,最长的等待时间约为15分钟。我想知道如何将超时设置为
ioutil.ReadAll(response.Body)
。结果证明这不是解决方案。它又永远阻塞了。看起来我仍然需要找到一种方法来设置此行的超时
ioutil.ReadAll(response.Body)
googleResponse := GoogleResponse{}
err = json.NewDecoder(io.LimitReader(resp.Body, MAX_MEMORY)).Decode(&googleResponse)
if err != nil {
    return nil, err
}