Доступ к объекту запроса gRPC в пользовательском перехватчике / промежуточном программном обеспечении - PullRequest
0 голосов
/ 26 июня 2018

Библиотека Go gRPC предоставляет интерфейсы для создания ваших собственных пользовательских перехватчиков (т.е. функций промежуточного программного обеспечения), и я пытаюсь написать два перехватчика регистрации.Первый - это унарный сервер-перехватчик, где я легко могу регистрировать параметры запроса, используя объект, переданный в функцию-перехватчик.

func loggingUnary(context context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
    start := time.Now()
    resp, err := handler(context, req)

    printLogMessage(err, info.FullMethod, context, time.Since(start), req)

    return resp, err
}

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

func loggingStream(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
    start := time.Now()
    err := handler(srv, stream)

    printLogMessage(err, info.FullMethod, stream.Context(), time.Since(start), "")

    return err
}

Ответы [ 2 ]

0 голосов
/ 01 октября 2018

Сейчас это немного устарело, но самый простой способ расширить ваш перехват в потоке - это создать обертку grpc.ServerStream , а затем обернуть настоящий ServerStream в ваш перехватчик.Таким образом, ваш перехватывающий код может обрабатывать полученные и отправленные сообщения в потоке.

// A wrapper for the real grpc.ServerStream
type LoggingServerStream struct {
    inner           grpc.ServerStream
}

func (l LoggingServerStream) SetHeader(m metadata.MD) error {
    return l.SetHeader(m)
}

func (l LoggingServerStream) SendHeader(m metadata.MD) error {
    return l.SendHeader(m)
}

func (l LoggingServerStream) SetTrailer(m metadata.MD) {
    l.SetTrailer(m)
}

func (l LoggingServerStream) Context() context.Context {
    return l.Context()
}

func (l LoggingServerStream) SendMsg(m interface{}) error {
    fmt.Printf("Sending Message: type=%s\n", reflect.TypeOf(m).String())
    return l.SendMsg(m)
}

func (l LoggingServerStream) RecvMsg(m interface{}) error {
    fmt.Printf("Receiving Message: type=%s\n", reflect.TypeOf(m).String())
    return l.RecvMsg(m)
}

Перехватчик:

func LoggingStreamInterceptor() grpc.StreamServerInterceptor {
    return func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
        return handler(srv, LoggingServerStream{inner:ss})
    }
}

Любое состояние, которое необходимо сохранить и перейти в свою оболочку..

0 голосов
/ 26 июня 2018

Обработчик потока может вызываться несколько раз за время существования запроса, который создал поток, поэтому запрос не является частью аргументов обработчика (и любого перехватчика, либо).Вы можете поместить запрос (или, лучше сказать, копию данных, которые вы хотите зарегистрировать, а не ссылку на сам запрос) в контексте потока (при условии, что вы контролируете код, который создает объект ServerStream).Я бы предпочел зарегистрировать параметры запроса один раз, когда создается поток, а не при каждом вызове обработчика (поэтому каждый запрос регистрируется только один раз).

...