Golang json 解码失败解码接口{}

Golang json decoding fails to decode interface{}

我正在使用一个库 (go-kit),它需要我指定函数来编码/解码我的请求和响应类型 to/from 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。我真的很想让我的代码保持干燥,避免使用数百个几乎相同的方法。因此,我尝试编写一个函数来生成解码给定请求类型的闭包:

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

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

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

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

您正在将 UpperCaseRequest 传递给 DecodeRequest 函数。在这个 func 中,参数是 interface{} 类型,它将这个参数的指针传递给 json 解码器。因此,解码器看到的是指向接口的指针,而不是指向 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{}}