Golang json解码无法解码接口{}

时间:2016-08-20 08:32:11

标签: json go unmarshalling

我正在使用一个库(go-kit),它要求我指定函数来编码/解码我的请求和响应类型到/来自JSON。对于编码,很简单:

func EncodeResponse(_ context.Context, w http.ResponseWriter, response interface{}) error {
    return json.NewEncoder(w).Encode(response)
}

我传递此函数来创建HTTP服务器,它工作正常。但是,他们提出的请求方法是单独使用以下形式的函数:

func decodeUppercaseRequest(_ context.Context, r *http.Request) (interface{}, error) {
    var req UppercaseRequest
    if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
        return nil, err
    }
    return req, nil
}

对于我的应用程序中的每个RPC。我真的想保持我的代码DRY并避免使用数百种几乎相同的方法。因此,我尝试编写一个函数来生成解码给定请求类型的闭包:

func DecodeRequest(req interface{}) httptransport.DecodeRequestFunc {
    return func(_ context.Context, r *http.Request) (interface{}, error) {
        if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
            return nil, err
        }
        return req, nil
    }
}

可以这样调用此函数:

DecodeRequest(UppercaseRequest{}}

不幸的是,当我这样做时,即使req的类型实际上是mypackage.UppercaseRequest,JSON解码也会失败。我不确定从哪里开始。有没有办法可以避免每个请求类型编写一个方法?有什么方法可以帮助Decode函数了解这种类型在运行时是什么?提前谢谢!

这是一个展示问题的游乐场: https://play.golang.org/p/GgHsLffp1G

1 个答案:

答案 0 :(得分:3)

根据您向我们展示的那段代码,我认为您正面临类型断言问题。我创建了一个playground to show you what I explain below

您正在将UpperCaseRequest传递给DecodeRequest func。在这个函数中,参数是interface {}类型,它将此参数的指针传递给json Decoder。因此,解码器会看到一个指向接口的指针,而不是指向UpperCaseRequest的指针。

这就是它没有被正确解码的原因。然后,尝试对其进行类型断言失败,因为断言两种不同的类型是不可能的。

所以,在你的代码中,我建议:

func DecodeRequest(req interface{}) httptransport.DecodeRequestFunc {
    return func(_ context.Context, r *http.Request) (interface{}, error) {
        // Note the '&' is removed here
        if err := json.NewDecoder(r.Body).Decode(req); err != nil {
            return nil, err
        }
        return req, nil
    }
}

并调用此函数:

// Note the & is placed here.
DecodeRequest(&UppercaseRequest{}}