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

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

报告相同问题?

悬赏问题

  • ¥20 mysql架构,按照姓名分表
  • ¥15 MATLAB实现区间[a,b]上的Gauss-Legendre积分
  • ¥15 Macbookpro 连接热点正常上网,连接不了Wi-Fi。
  • ¥15 delphi webbrowser组件网页下拉菜单自动选择问题
  • ¥15 linux驱动,linux应用,多线程
  • ¥20 我要一个分身加定位两个功能的安卓app
  • ¥15 基于FOC驱动器,如何实现卡丁车下坡无阻力的遛坡的效果
  • ¥15 IAR程序莫名变量多重定义
  • ¥15 (标签-UDP|关键词-client)
  • ¥15 关于库卡officelite无法与虚拟机通讯的问题