doubu1853
doubu1853
2016-08-20 08:32

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 dongtiaozhou4914 5年前

    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{}}
    
    点赞 评论 复制链接分享

相关推荐