duanke8011 2019-02-01 07:33
浏览 609
已采纳

Golang * bytes.Buffer nil会导致致命错误[关闭]

I had the same issue as https://github.com/golang/go/issues/26666 because I have a wrap function for my http requests.

Sometimes I need to request:

body := new(bytes.Buffer)
json.NewEncoder(body).Encode(h)
req("POST", "http://example.com", body)

And sometimes it's simply:

req("GET", "http://example.com", nil)
runtime error: invalid memory address or nil pointer dereference

I ended up with:

req("GET", "http://example.com", new(bytes.Buffer))

But I'm not sure if it's the right thing to do.

The function:

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
}

Updated function:

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)
    }
}
  • 写回答

1条回答 默认 最新

  • dqaq59269 2019-02-01 08:13
    关注

    The body in http.NewRequest() is optional, so passing nil is acceptable when you're doing GET requests.

    The problem is that the body parameter of http.NewRequest is an interface type: io.Reader, and you're attempting to pass a value of a concrete type *bytes.Buffer. What happens is that this nil pointer will be wrapped in a non-nil interface value, and that will be passed to http.NewRequest as the body.

    If you don't have a body, pass nil explicitly, like this:

    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)
    
        // ....
    }
    

    And then you can call it like:

    req("GET", "http://example.com", nil)
    

    Although best would be if your req() function would take io.Reader in the first place, so you don't have to check its value explicitly:

    func req(method string, url string, body io.Reader) int {
        req, err := http.NewRequest(method, url, body) // You may pass it as-is
    
        // ....
    }
    

    And you can call it with nil or with a non-nil *bytes.Buffer too:

    req("GET", "http://example.com", nil) // OK
    
    req("POST", "http://example.com", bytes.NewBufferString("data")) // Also OK
    

    For more details, see Hiding nil values, understanding why golang fails here

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 乌班图ip地址配置及远程SSH
  • ¥15 怎么让点阵屏显示静态爱心,用keiluVision5写出让点阵屏显示静态爱心的代码,越快越好
  • ¥15 PSPICE制作一个加法器
  • ¥15 javaweb项目无法正常跳转
  • ¥15 VMBox虚拟机无法访问
  • ¥15 skd显示找不到头文件
  • ¥15 机器视觉中图片中长度与真实长度的关系
  • ¥15 fastreport table 怎么只让每页的最下面和最顶部有横线
  • ¥15 java 的protected权限 ,问题在注释里
  • ¥15 这个是哪里有问题啊?