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{}}
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 YoloV5 第三方库的版本对照问题
  • ¥15 请完成下列相关问题!
  • ¥15 drone 推送镜像时候 purge: true 推送完毕后没有删除对应的镜像,手动拷贝到服务器执行结果正确在样才能让指令自动执行成功删除对应镜像,如何解决?
  • ¥15 求daily translation(DT)偏差订正方法的代码
  • ¥15 js调用html页面需要隐藏某个按钮
  • ¥15 ads仿真结果在圆图上是怎么读数的
  • ¥20 Cotex M3的调试和程序执行方式是什么样的?
  • ¥20 java项目连接sqlserver时报ssl相关错误
  • ¥15 一道python难题3
  • ¥15 牛顿斯科特系数表表示