doubu1853 2016-08-20 08:32
浏览 69
已采纳

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

I'm using a library (go-kit) which requires I specify functions to encode / decode my request and response types to/from JSON. For encoding, it is simple:

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

I pass this function to create the HTTP server and it works fine. However, their proposed approach for requests is to make a separate function of the form:

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
}

For every single RPC in my application. I would really like to keep my code DRY and avoid having hundreds of almost identical methods. As such, I attempted to write a function to generate closures that decode the given request type:

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

This function can be called like so:

DecodeRequest(UppercaseRequest{}}

Unfortunately, when I do so, the JSON decoding fails, even though the type of req is in fact mypackage.UppercaseRequest. I'm not sure where to go from here. Is there a way I can avoid having to write a method per request type? Is there some way I can help the Decode function understand what this type is at runtime? Thanks in advance!

Here is a go playground demonstrating the issue: https://play.golang.org/p/GgHsLffp1G

  • 写回答

1条回答 默认 最新

  • dongtiaozhou4914 2016-08-20 13:53
    关注

    According to the piece of code you are showing us, I think you are facing a type assertion issue. I created a playground to show you what I explain below.

    You're passing a UpperCaseRequest to DecodeRequest func. In this func, the argument is of type interface{}, and it passes a pointer of this argument to the json Decoder. So, The decoder sees a pointer to interface, and not a pointer to UpperCaseRequest.

    This is why it's not correctly decoded. And then, trying a type assertion on it fails because asserting two different type is not possible.

    So, in your code, I'd suggest:

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

    And call this function like this:

    // Note the & is placed here.
    DecodeRequest(&UppercaseRequest{}}
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥20 sub地址DHCP问题
  • ¥15 delta降尺度计算的一些细节,有偿
  • ¥15 Arduino红外遥控代码有问题
  • ¥15 数值计算离散正交多项式
  • ¥30 数值计算均差系数编程
  • ¥15 redis-full-check比较 两个集群的数据出错
  • ¥15 Matlab编程问题
  • ¥15 训练的多模态特征融合模型准确度很低怎么办
  • ¥15 kylin启动报错log4j类冲突
  • ¥15 超声波模块测距控制点灯,灯的闪烁很不稳定,经过调试发现测的距离偏大