简体   繁体   English

Grpc-gateway:如何处理非json请求体?

[英]Grpc-gateway: how to deal with non-json request body?

Grpc-gateway offers solutions for customizing response body using google.api.HttpBody (non-json content type like text/plain , application/xml , etc), however, this proto message cannot deal with request body. Grpc-gateway 提供了使用google.api.HttpBody (非 json 内容类型,如text/plainapplication/xml等)自定义响应正文的解决方案,但是,此 proto 消息无法处理请求正文。

Inspired by johanbrandhorst' comment , I came up with a solution with a customized marshaler.受到johanbrandhorst 评论的启发,我想出了一个带有定制编组器的解决方案。 I implemented interfaces of runtime.marshaler to create my own marshaler.我实现了runtime.marshaler的接口来创建我自己的 marshaler。

Custiomized marshaler自定义编组器

package marshaler

import (
    "errors"
    "io"
    "io/ioutil"
    "log"
    "reflect"

    "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
    "google.golang.org/genproto/googleapis/api/httpbody"
)

type XMLMarshaler struct {
    runtime.Marshaler
}

func (x XMLMarshaler) ContentType(_ interface{}) string {
    return "application/xml"
}

func (x XMLMarshaler) Marshal(v interface{}) ([]byte, error) {
    log.Println("xml marshal")
    log.Printf("param: %+v", v)
    // return xml.Marshal(v)
    if httpBody, ok := v.(*httpbody.HttpBody); ok {
        return httpBody.Data, nil
    }
    return x.Marshaler.Marshal(v)
}

func (x XMLMarshaler) NewDecoder(r io.Reader) runtime.Decoder {
    log.Println("xml new decoder")
    return runtime.DecoderFunc(func(p interface{}) error {
        buffer, err := ioutil.ReadAll(r)
        if err != nil {
            return err
        }

        pType := reflect.TypeOf(p)
        if pType.Kind() == reflect.Ptr {
            v := reflect.Indirect(reflect.ValueOf(p))
            if v.Kind() == reflect.String {
                v.Set(reflect.ValueOf(string(buffer)))
                return nil
            }
        }
        return errors.New("value type error")
    })
}

starting grpc-gateway启动 grpc 网关

func run() error {
    ctx := context.Background()
    ctx, cancel := context.WithCancel(ctx)
    defer cancel()

    // Register gRPC server endpoint
    // Note: Make sure the gRPC server is running properly and accessible
    mux := runtime.NewServeMux(
        runtime.WithMarshalerOption("application/xml", marshaler.XMLMarshaler{}),
    )
    opts := []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}
    err := gw.RegisterBotServiceHandlerFromEndpoint(ctx, mux, *grpcServerEndpoint, opts)
    if err != nil {
        return err
    }

    // Start HTTP server (and proxy calls to gRPC server endpoint)
    return http.ListenAndServe(":8080", mux)
}

Then, for all requests with content type specified as "application/xml", grpc-gateway will assign the XML body data to google.api.HttpBody.Data .然后,对于内容类型指定为“application/xml”的所有请求, grpc-gateway会将 XML 正文数据分配给google.api.HttpBody.Data And, for non-json responses, grpc-gateway will assign google.api.HttpBody.Data to response body.而且,对于非 json 响应, grpc-gateway会将google.api.HttpBody.Data分配给响应正文。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM