Http Golang*bytes.Buffer nil导致致命错误
我遇到了与相同的问题,因为我有一个用于http请求的wrap函数 有时我需要请求:Http Golang*bytes.Buffer nil导致致命错误,http,pointers,go,interface,Http,Pointers,Go,Interface,我遇到了与相同的问题,因为我有一个用于http请求的wrap函数 有时我需要请求: body := new(bytes.Buffer) json.NewEncoder(body).Encode(h) req("POST", "http://example.com", body) 有时它只是: req("GET", "http://example.com", nil) runtime error: invalid memory address or nil pointer dereference
body := new(bytes.Buffer)
json.NewEncoder(body).Encode(h)
req("POST", "http://example.com", body)
有时它只是:
req("GET", "http://example.com", nil)
runtime error: invalid memory address or nil pointer dereference
我的结局是:
req("GET", "http://example.com", new(bytes.Buffer))
但我不确定这样做是否正确。
职能:
func req(method string, url string, body *bytes.Buffer) int {
req, err := http.NewRequest(method, url, body)
req.Header.Set("Content-Type", "application/json")
req.SetBasicAuth(user, psw)
resp, err := client.Do(req)
checkErr(err)
if resp.StatusCode > 500 {
time.Sleep(30 * time.Second)
resp, err = client.Do(req)
checkErr(err)
}
defer resp.Body.Close()
return resp.StatusCode
}
更新的功能:
func req(method string, url string, body io.Reader) int {
req, err := http.NewRequest(method, url, body)
req.Header.Set("Content-Type", "application/json")
req.SetBasicAuth(user, psw)
resp, err := client.Do(req)
checkErr(err)
defer resp.Body.Close()
if resp.StatusCode >= 500 {
time.Sleep(30 * time.Second)
req, err := http.NewRequest(method, url, body)
req.Header.Set("Content-Type", "application/json")
req.SetBasicAuth(user, psw)
resp, err := client.Do(req)
checkErr(err)
defer resp.Body.Close()
}
return resp.StatusCode
}
func checkErr(err error) {
if err != nil {
log.Fatal(err)
}
}
body
in是可选的,因此在执行GET
请求时传递nil
是可以接受的
问题在于http.NewRequest
的body
参数是一种接口类型:io.Reader
,您试图传递具体类型的值*bytes.Buffer
。发生的情况是,这个nil
指针将被包装在一个非nil
接口值中,并作为主体传递给http.NewRequest
如果没有实体,请显式传递nil
,如下所示:
func req(method string, url string, body *bytes.Buffer) int {
var bodyToPass io.Reader
if body != nil {
bodyToPass = body
}
req, err := http.NewRequest(method, url, bodyToPass)
// ....
}
然后你可以这样称呼它:
req("GET", "http://example.com", nil)
虽然最好的方法是,如果您的req()
函数首先使用io.Reader
,那么您不必显式检查它的值:
func req(method string, url string, body io.Reader) int {
req, err := http.NewRequest(method, url, body) // You may pass it as-is
// ....
}
您可以使用nil
或非nil
*字节来调用它。缓冲区也可以:
req("GET", "http://example.com", nil) // OK
req("POST", "http://example.com", bytes.NewBufferString("data")) // Also OK
有关更多详细信息,请参见“但我不确定这样做是否正确。”如果您的程序出现故障,则答案是“这样做不正确”。嘿,它起作用了!:)我担心这看起来是否愚蠢。正在学习:不要忽略http.NewRequest返回的错误。checkErr做什么?如果它没有终止程序,你必须在调用它后返回。您没有关闭501+响应的主体(您的意思是=
?)您的代码有一个微妙的问题,如果第一个resp
的StatusCode>500,您将发出另一个请求并使用结果覆盖原始resp
值,而从未对原始resp
调用Body.Close()
。如果有足够的时间和足够的500多个响应,这将导致您的程序耗尽文件描述符并最终崩溃。您需要关闭两个响应的主体。还有一件事:您不能重复使用req值进行重试,因为它的主体已经被读取。您必须创建一个新请求。感谢您的帮助。我已经更新了“func req”。你认为这是对的吗?@raimondsinde调用log.Fatal()
几乎从来都不对。您可以在一个快速演示中这样做,但在生产代码中,您永远不会希望这样做。相反,返回错误并让调用者处理它。