使用net/http发送GET请求body为空时报错

1. 运行环境

go version go1.16.12 linux/amd64 Centos 7.9

2. 问题描述?

使用以下httpClientDo发送Get请求时,当data为nil时报错

func httpClientDo(method, url, token string, data interface{}) (*http.Response, error) {
    var body *bytes.Buffer
    if data != nil {
        log.Info("body is not nil")
        var buf bytes.Buffer
        if err := json.NewEncoder(&buf).Encode(data); err != nil {
            log.Errorf("failed to encode data to body buffer, err:" + err.Error())
            return nil, err
        }
        log.Info(buf.String())
        body = &buf
    }

    req, err := http.NewRequest(method, url, body)
    if err != nil {
        log.Errorf("failed to create new request, err:" + err.Error())
        return nil, err
    }

    req.Header.Set("Content-Type", "application/json")
    if token != "" {
        req.Header.Set("X-Auth-Token", token)
    }

    resp, err := (&http.Client{}).Do(req)
    if err != nil {
        log.Errorf("failed to call http " + method + ", err: " + err.Error())
        return nil, err
    }

    return resp, nil
}

报错信息见后面。

看了具体的代码段,是NewRequest body参数不为空才会走的流程,但是httpClientDo里data != nil 这边没有打印出来,所以不清楚为什么

3. 您期望得到的结果?

不会报错
//: <> (能截图就截图。)

4. 您实际得到的结果?

错误信息,见下
//: <> (有报错信息的话把堆栈信息提供出来)

runtime error: invalid memory address or nil pointer dereference
/usr/local/go/src/runtime/panic.go:212 (0x43597a)
    panicmem: panic(memoryError)
/usr/local/go/src/runtime/signal_unix.go:734 (0x44e572)
    sigpanic: panicmem()
/usr/local/go/src/bytes/buffer.go:73 (0x743af1)
    (*Buffer).Len: func (b *Buffer) Len() int { return len(b.buf) - b.off }
/usr/local/go/src/net/http/request.go:890 (0x743af9)
    NewRequestWithContext: req.ContentLength = int64(v.Len())
/usr/local/go/src/net/http/request.go:828 (0xa97fab)
    NewRequest: return NewRequestWithContext(context.Background(), method, url, body)
/data/go/src/arena/controller/internal/service/http_util.go:24 (0xa985e9)
    httpClientDo: req, err := http.NewRequest(method, url, body)
/data/go/src/arena/controller/internal/service/compute_agent.go:478 (0xa96439)
    (*ResourceManager).GetNextTerminalAssetDetail: addResp, err := httpClientDo("GET", nextTerminalAddAssetURL, respBody.Data, nil)
/data/go/src/arena/controller/internal/service/next_terminal.go:38 (0xa9e517)
    (*ResourceManager).CreateNextTerminalURL: ntAsset, err := manager.GetNextTerminalAssetDetail(req.Instance)
/data/go/src/arena/controller/internal/server/controller/next_terminal.go:20 (0xaae06d)
    (*ArenaController).CreateNextTerminalURL: net, err := ac.ResourceManager.CreateNextTerminalURL(&req)
/data/go/pkg/mod/github.com/gin-gonic/gin@v1.7.4/context.go:165 (0x9bc239)
    (*Context).Next: c.handlers[c.index](c)
/data/go/pkg/mod/github.com/gin-gonic/gin@v1.7.4/recovery.go:99 (0x9bc220)
    CustomRecoveryWithWriter.func1: c.Next()
/data/go/pkg/mod/github.com/gin-gonic/gin@v1.7.4/context.go:165 (0x9bb313)
    (*Context).Next: c.handlers[c.index](c)
/data/go/pkg/mod/github.com/gin-gonic/gin@v1.7.4/logger.go:241 (0x9bb2d2)
    LoggerWithConfig.func1: c.Next()
/data/go/pkg/mod/github.com/gin-gonic/gin@v1.7.4/context.go:165 (0x9b16a9)
    (*Context).Next: c.handlers[c.index](c)
/data/go/pkg/mod/github.com/gin-gonic/gin@v1.7.4/gin.go:489 (0x9b168f)
    (*Engine).handleHTTPRequest: c.Next()
/data/go/pkg/mod/github.com/gin-gonic/gin@v1.7.4/gin.go:445 (0x9b117b)
    (*Engine).ServeHTTP: engine.handleHTTPRequest(c)
/usr/local/go/src/net/http/server.go:2868 (0x755402)
    serverHandler.ServeHTTP: handler.ServeHTTP(rw, req)
/usr/local/go/src/net/http/server.go:1933 (0x75082c)
    (*conn).serve: serverHandler{c.server}.ServeHTTP(w, w.req)
/usr/local/go/src/runtime/asm_amd64.s:1371 (0x46e200)
    goexit: BYTE    $0x90    // NOP
讨论数量: 1

stackoverflow.com/questions/544748...

参考相同的问题,大概原因是GET请求请直接将body指为nil。因为方法需要的类型是 io.Reader,而实际传递过去的是个 *bytes.Buffer nil指针会被包装为非nil的 interface type。

3年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!