Golaong invalid character ‘\x00’ after top-level value
1 概述
当我们无法无法判断需要创建的字节切片A的长度的时候,通常会创建一个较大长度的空字节切片B来接收未知长度的字节,当使用json.Unmarshal解析字节的时候,就会出现 panic invalid character ‘\x00’ after top-level value 的错误,这是因为B切片的长度实际大于A所需的长度,Json读取到nil的时候,会停止继续读取, 造成多出一个\x00,而json无法解析\x00
错误日志
2020/07/31 13:44:14 [Recovery] 2020/07/31 - 13:44:14 panic recovered:
POST /price HTTP/1.1
Host: localhost:8080
Accept: */*
Accept-Encoding: gzip, deflate, br
Cache-Control: no-cache
Connection: keep-alive
Content-Length: 133
Content-Type: application/json
Postman-Token: 97f9e99a-4e28-4d3b-a241-372efbcf4ee4
User-Agent: PostmanRuntime/7.26.2
invalid character '\x00' after top-level value
D:/Library/Code/Projects/cloud-price/main.go:23 (0xa9a0ee)
main.func1: panic(err)
C:/Users/Mist/go/pkg/mod/github.com/gin-gonic/[email protected]/context.go:161 (0xa7a91f)
(*Context).Next: c.handlers[c.index](c)
C:/Users/Mist/go/pkg/mod/github.com/gin-gonic/[email protected]/recovery.go:83 (0xa96ca7)
RecoveryWithWriter.func1: c.Next()
C:/Users/Mist/go/pkg/mod/github.com/gin-gonic/[email protected]/context.go:161 (0xa7a91f)
(*Context).Next: c.handlers[c.index](c)
C:/Users/Mist/go/pkg/mod/github.com/gin-gonic/[email protected]/logger.go:241 (0xa9578b)
LoggerWithConfig.func1: c.Next()
C:/Users/Mist/go/pkg/mod/github.com/gin-gonic/[email protected]/context.go:161 (0xa7a91f)
(*Context).Next: c.handlers[c.index](c)
C:/Users/Mist/go/pkg/mod/github.com/gin-gonic/[email protected]/gin.go:409 (0xa878bb)
(*Engine).handleHTTPRequest: c.Next()
C:/Users/Mist/go/pkg/mod/github.com/gin-gonic/[email protected]/gin.go:367 (0xa8736c)
(*Engine).ServeHTTP: engine.handleHTTPRequest(c)
D:/Go/src/net/http/server.go:2774 (0x7be64c)
serverHandler.ServeHTTP: handler.ServeHTTP(rw, req)
D:/Go/src/net/http/server.go:1878 (0x7b8d09)
(*conn).serve: serverHandler{c.server}.ServeHTTP(w, w.req)
D:/Go/src/runtime/asm_amd64.s:1337 (0x45f4e0)
goexit: BYTE $0x90 // NOP
2 解决方法
在B接收A后,可用A的长度截取切片,在传递至 json.Unmarshal 解析
// 创建一个容量和长度都是2048的字节切片
buffer := make([]byte, 2048)
...
// Read 会返回 Body 字节的长度length,然后使用length截取切片 buffer[:length],再解析
json.Unmarshal(buffer[:length], &request)
3 code
这里以gin的post请求为例
package main
import (
"fmt"
"encoding/json"
"github.com/gin-gonic/gin"
)
func main(){
fmt.Println("Hello Rain")
route := gin.Default()
route.POST("/price", func(c * gin.Context){
// 创建一个容量和长度都是2048的字节切片
buffer := make([]byte, 2048)
var request struct{
Action string
Component string
Params interface{}
RequestID string
Version int64
}
// Read 会返回 Body 字节的长度length,然后使用length截取切片 buffer[:length],再解析
length,_ := c.Request.Body.Read(buffer)
if err := json.Unmarshal(buffer[:length], &request); err!=nil{
panic(err)
}
fmt.Println("body: ", request)
c.JSON(200, gin.H{
"author": "rain",
})
})
route.GET("/file")
route.Run()
}