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 如何用Labview在myRIO上做LCD显示?(语言-开发语言)
  • ¥15 Vue3地图和异步函数使用
  • ¥15 C++ yoloV5改写遇到的问题
  • ¥20 win11修改中文用户名路径
  • ¥15 win2012磁盘空间不足,c盘正常,d盘无法写入
  • ¥15 用土力学知识进行土坡稳定性分析与挡土墙设计
  • ¥70 PlayWright在Java上连接CDP关联本地Chrome启动失败,貌似是Windows端口转发问题
  • ¥15 帮我写一个c++工程
  • ¥30 Eclipse官网打不开,官网首页进不去,显示无法访问此页面,求解决方法
  • ¥15 关于smbclient 库的使用