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