一年多前,Go为Offset
类型添加了json.UnmarshalTypeError
值(有关上下文,请参阅已结束的问题here)。偏移值背后的目的是有意义的,但我不确定在读取一个类型为io.ReadCloser
的go http响应体时如何使用它。
// An UnmarshalTypeError describes a JSON value that was
// not appropriate for a value of a specific Go type.
type UnmarshalTypeError struct {
Value string // description of JSON value - "bool", "array", "number -5"
Type reflect.Type // type of Go value it could not be assigned to
Offset int64 // error occurred after reading Offset bytes
}
例如:
var body CustomType
decoderErr := json.NewDecoder(response.Body).Decode(&body)
if decoderErr != nil {
if typeError, ok := decoderErr.(*json.UnmarshalTypeError); ok {
// Do something with typeError.Offset here
}
}
在发现错误时,我已经通过response.Body
从json.NewDecoder...
读取。我正在寻找一种方法来再次读取response.Body
,但只能通过使用typeError中的Offset值来达到错误点。
答案 0 :(得分:2)
由于你想重用请求体,你应该在解组体之前读取并存储体,然后如果存在JSON语法或类型错误,你可以使用之前存储的体返回更有用的错误。
概念证明:
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
)
type Hello struct {
Name string `json:"name"`
Message string `json:"message"`
}
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
b, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, "Error reading body", 400)
return
}
h := &Hello{}
if err := json.Unmarshal(b, &h); err != nil {
var msg string
switch t := err.(type) {
case *json.SyntaxError:
jsn := string(b[0:t.Offset])
jsn += "<--(Invalid Character)"
msg = fmt.Sprintf("Invalid character at offset %v\n %s", t.Offset, jsn)
case *json.UnmarshalTypeError:
jsn := string(b[0:t.Offset])
jsn += "<--(Invalid Type)"
msg = fmt.Sprintf("Invalid value at offset %v\n %s", t.Offset, jsn)
default:
msg = err.Error()
}
http.Error(w, msg, 400)
return
}
w.Write([]byte(`Good to go!`))
})
if err := http.ListenAndServe(":8000", nil); err != nil {
log.Fatal(err)
}
}