douwuying4709 2016-11-22 17:41
浏览 333
已采纳

如何在encoding / json UnmarshalTypeError中使用偏移值,以更好地处理错误?

A little over a year ago, Go added an Offset value to the json.UnmarshalTypeError type (see closed issue here for context). The purpose behind the offset value makes sense, but I'm not sure how it can be used when reading a go http response body, which is of type io.ReadCloser.

// 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
}

For example:

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
    }


}

At the point of the error getting caught, I've already read from response.Body via json.NewDecoder.... I'm looking for a way to read response.Body again, but only up to the point of the error by using the Offset value in typeError.

  • 写回答

1条回答 默认 最新

  • dongyuan8469 2016-11-22 18:56
    关注

    Since you want to reuse the request body you should read and store the body before you Unmarshal the body, then if there is a JSON syntax or type error you can return a more useful error using the body you previously stored.

    Proof of concept:

    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
     %s", t.Offset, jsn)
                case *json.UnmarshalTypeError:
                    jsn := string(b[0:t.Offset])
                    jsn += "<--(Invalid Type)"
                    msg = fmt.Sprintf("Invalid value at offset %v
     %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)
        }
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 如何在scanpy上做差异基因和通路富集?
  • ¥20 关于#硬件工程#的问题,请各位专家解答!
  • ¥15 关于#matlab#的问题:期望的系统闭环传递函数为G(s)=wn^2/s^2+2¢wn+wn^2阻尼系数¢=0.707,使系统具有较小的超调量
  • ¥15 FLUENT如何实现在堆积颗粒的上表面加载高斯热源
  • ¥30 截图中的mathematics程序转换成matlab
  • ¥15 动力学代码报错,维度不匹配
  • ¥15 Power query添加列问题
  • ¥50 Kubernetes&Fission&Eleasticsearch
  • ¥15 報錯:Person is not mapped,如何解決?
  • ¥15 c++头文件不能识别CDialog