Golang JSON декодирования не может декодировать интерфейс {}

json go unmarshalling

1520 просмотра

1 ответ

Я использую библиотеку (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 в моем приложении. Мне бы очень хотелось, чтобы мой код был СУХИМ, и чтобы в нем не было сотен почти идентичных методов. Поэтому я попытался написать функцию для генерации замыканий, которые декодируют данный тип запроса:

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-декодирование завершается неудачно, хотя тип req на самом деле mypackage.UppercaseRequest. Я не уверен, куда идти отсюда. Есть ли способ избежать написания метода для каждого типа запроса? Есть ли какой-нибудь способ помочь функции декодирования понять, что это за тип во время выполнения? Заранее спасибо!

Вот игровая площадка, демонстрирующая проблему: https://play.golang.org/p/GgHsLffp1G

Автор: Logan Shire Источник Размещён: 08.11.2019 11:04

Ответы (1)


3 плюса

Решение

В соответствии с фрагментом кода, который вы нам показываете, я думаю, что вы столкнулись с проблемой утверждения типа. Я создал игровую площадку, чтобы показать вам, что я объясняю ниже .

Вы передаете UpperCaseRequest в функцию DecodeRequest. В этой функции аргумент имеет тип интерфейса {}, и он передает указатель этого аргумента в декодер 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{}}
Автор: jnmoal Размещён: 20.08.2016 01:53
Вопросы из категории :
32x32