Gokit: проверка запроса / полезной нагрузки на транспортном уровне

#go #rpc #endpoint #transport-layer-protocol

#Вперед #rpc #конечная точка #протокол транспортного уровня

Вопрос:

Я использую go-kit для создания конечной точки RPC. Я создаю конечную точку, подобную этой

 httptransport.NewServer(
    endPoint.MakeGetBlogEndPoint(blogService),
    transport.DecodeGetBlogRequest,
    transport.EncodeGetBlogResponse
 

Ниже приведена моя функция DecodeGetBlogRequest

 func DecodeGetBlogRequest(c context.Context, r *http.Request) (interface{}, error) {
        vars := mux.Vars(r)
        id, err := strconv.Atoi(vars["id"])
        if err != nil {
            return nil, err
        }
        req := endPoint.GetBlogRequest{
            ID: id,
        }
        return req, nil
    }
 

Что я хочу сделать, так это проверить HTTP-запрос в этой функции и, если он признан недействительным, отправить ответ с допустимым кодом ошибки только отсюда, не передавая его на уровень обслуживания. т.Е. Если ID не является допустимым числом, верните 400 Bad Request ответ отсюда.

Но поскольку у меня нет ссылки ResponseWriter в этой функции, я не уверен, как это сделать.

Я следую этому примеру из документов go-kit https://gokit.io/examples/stringsvc.html

Допустимо ли предположение, что запрос / полезная нагрузка должна проверяться только на транспортном уровне, а уровень обслуживания должен вызываться только в том случае, если запрос / полезная нагрузка действительны? Если да, то как это сделать в этом примере?

Ответ №1:

Вы можете использовать ServerErrorEncoder, который возвращает параметры сервера (можно найти в github.com/go-kit/kit/transport/server.go ). В основном на вашем транспортном уровне, помимо функций Decode и Encode, вы можете определить функцию YourErrorEncoderFunc(), которая может выглядеть следующим образом. Это перехватит любую ошибку, выданную на транспортном уровне.
YourErrorEncoderFunc(_ context.Context, ошибка ошибки, w http.ResponseWriter).

Вам нужно будет подключить эту функцию в качестве опции при регистрации конечной точки, например:

 ABCOpts := []httptransport.ServerOption{
            httptransport.ServerErrorEncoder(YourErrorEncoderFunc),
            }

r.Methods("GET").Path("/api/v1/abc/def").Handler(httptransport.NewServer(
    endpoints.GetDataEndpoint,
    DecodeGetRequest,
    EncodeGetResponse,
    ABCOpts...,
))
 

Это остановится на транспортном уровне, если проверка вашего запроса недействительна, и вызовет ошибку в http-ответе на основе любого формата, который вы написали в своем errorencoderfunc() .

Ответ №2:

Не уверен на 100%, относится ли это go-kit также и к grpc:

У вас есть возвращаемая переменная с ошибкой. Используйте это, чтобы указать на наличие проблемы. В модуле go grpc есть пакет состояния для возврата ошибок с кодами состояния. Если вы возвращаете ошибку с кодом состояния, уровень grpc возьмет код из ошибки и отправит его обратно.

Например:

 func DecodeGetBlogRequest(c context.Context, r *http.Request) (interface{}, error) {
        vars := mux.Vars(r)
        id, err := strconv.Atoi(vars["id"])
        if err != nil {
            return nil, status.Error(codes.InvalidArgument, err.Error())
        }
        req := endPoint.GetBlogRequest{
            ID: id,
        }
        return req, nil
    }
 

Также обратите внимание, что grpc использует разные коды состояния. В Go они находятся в пакете codes.

Комментарии:

1. Ваш ответ привел меня к моему решению. Я начал искать «что-то вроде status package» в go-kit и нашел решение, которое является ServerErrorEncoder функцией. Спасибо.