"invalid memory address …"的图像来源是http.client。

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

Figure source of "invalid memory address ... " with http.client

问题

我正在学习Go语言,但是在处理panic错误方面遇到了困难...它能够工作一段时间,但最终会出现类似于panic: runtime error: invalid memory address or nil pointer dereference的异常。

这个函数简单地遍历代理的映射,直到成功获取到"address"的内容为止。这可能不是很符合惯用法,特别是使用映射而不是切片以及最后的返回语句,但我希望这不是导致panic错误的原因...
如果我遗漏了一些可能重要的东西,请告诉我,我会更新帖子,我只是不想用不必要的信息淹没它。
proxies是一个具有映射字段和用于并发安全读取/删除的方法的结构体。

func getContent(address string) string {
	localProxies := proxies.Get()
	for proxy := range localProxies {
		proxyUrl, _ := url.Parse("http://" + proxy)

		transport := http.Transport{
			Dial:  dialTimeout,
			Proxy: http.ProxyURL(proxyUrl),
		}
		httpClient := http.Client{Transport: &transport, Timeout: timeout}
		req, err := http.NewRequest("GET", address, nil)
		if err != nil {
			fmt.Println("Request error: ", err.Error())
		}
		req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0")
		res, err := httpClient.Do(req)
		defer res.Body.Close()

		if err != nil {
			//			fmt.Println("Broken ", proxy)
			fmt.Println("Response error: ", err.Error())
			proxies.Del(proxy)
			continue
		}
		if res.StatusCode != 200 {
			//			fmt.Println("Status error: ", res.Status)
			proxies.Del(proxy)
			continue
		}
		out, err := ioutil.ReadAll(res.Body)
		if err != nil {
			fmt.Println("Read error: ", err.Error())
			proxies.Del(proxy)
			continue
		}
		return string(out)
	}
	return "error"
}

go version go1.4.2 linux/amd64
英文:

I learning the go and struggling with this panic error... it working for some time, but soon end up with such exception panic: runtime error: invalid memory address or nil pointer dereference

The function simply iterate over map of proxies until it successfully get the content of the "address". It must be not very idiomatic, especially using map instead of slice and the last return, but I hope that is not the reason of panic crush...
if I omitted something possible important please, let me know, I will update the post, I just do not want to flood it with unnecessary info.
proxies is a struct with map field with methods for concurrent safe read/delete.

func getContent(address string) string {
localProxies := proxies.Get()
for proxy := range localProxies {
	proxyUrl, _ := url.Parse("http://" + proxy)

	transport := http.Transport{
		Dial:  dialTimeout,
		Proxy: http.ProxyURL(proxyUrl),
	}
	httpClient := http.Client{Transport: &transport, Timeout: timeout}
	req, err := http.NewRequest("GET", address, nil)
	if err != nil {
		fmt.Println("Request error: ", err.Error())
	}
	req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0")
	res, err := httpClient.Do(req)
	defer res.Body.Close()

	if err != nil {
		//			fmt.Println("Broken ", proxy)
		fmt.Println("Response error: ", err.Error())
		proxies.Del(proxy)
		continue
	}
	if res.StatusCode != 200 {
		//			fmt.Println("Status error: ", res.Status)
		proxies.Del(proxy)
		continue
	}
	out, err := ioutil.ReadAll(res.Body)
	if err != nil {
		fmt.Println("Read error: ", err.Error())
		proxies.Del(proxy)
		continue
	}
	return string(out)
}
return "error"

}

go version go1.4.2 linux/amd64

答案1

得分: 5

在我看到更多信息之前,这只是根据你发布的代码所能获取的信息的猜测。

调用

res.Body.Close()

应该放在错误检查之后,而不是之前。所以将代码改为:

 res, err := httpClient.Do(req)
 if err != nil {
     ...
 }
 defer res.Body.Close()
英文:

Until I see more information, this is simply a guess based on what I could gather from the code you posted.

The call

res.Body.Close()

should come after your check for error, not before. So change:

 res, err := httpClient.Do(req)
 defer res.Body.Close()
 if err != nil {
     ...
 }

to

 res, err := httpClient.Do(req)
 if err != nil {
     ...
 }
 defer res.Body.Close()

huangapple
  • 本文由 发表于 2015年4月24日 14:38:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/29840375.html
匿名

发表评论

匿名网友

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

确定