我在同一个 go 应用中使用 grpc-gateway
,代理将 HTTP 转换为 GRPC。据我所知,默认情况下 grpc-gateway
为所有 rpc 设置应用程序 application/json
格式,包括流式传输。
所以,我的任务是:
Content-type: application/json
,否则请求应被拒绝并根据 RFC 发送 406。Accept: application/x-ndjson
,为服务器流设置 Accept: applcation/x-ndjson
标头。如果条件不满足 406,则应返回。Content-type: applicaiton/json
,为服务器流设置 Content-type: application/x-ndjson
。因此,grpc-gateway
仅建议为 application/x-ndjson
设置自定义编组器,这实际上与默认设置相同,因此只需覆盖 ContentType
方法。这种方法不允许我为每个方法调用设置封送拆收器,并且不允许我拒绝每个请求不受支持的内容类型。
我怎样才能在仍然使用 grpc-gateway
的情况下实现这一目标?或者我应该考虑手动实现http grpc转换?
答案 0 :(得分:0)
我建议您不要使用 grpc-gateway 或任何其他工具将 gRPC 转换为 HTTP RPC。您给应用程序增加了不必要的复杂性。
如果您有 gRPC 服务,但无论出于何种原因,您的客户端无法调用 gRPC,您需要通过普通 HTTP 选项提供您的服务...是您的情况吗?
如果是这种情况,正确的方法是提供 HTTP RPC 服务,并从中调用 gRPC 服务。
HTTP RPC 比 REST 简单得多,您不需要任何工具。
我在 GOlang here
中实现了这个确切的案例 // Creates a new book.
func (h BookStoreService) CreateBook(w http.ResponseWriter, r *http.Request) {
request := &bookv1.CreateBookRequest{}
proxy := httputil.GetProxy(w, r, request)
proxy.SetServiceRequest(func(request proto.Message) (proto.Message, error) {
return h.client.CreateBook(r.Context(), request.(*bookv1.CreateBookRequest))
})
proxy.Call()
}
代理结构
func GetProxy(w http.ResponseWriter, r *http.Request, request proto.Message) *ServiceProxy {
proxy := &ServiceProxy{}
proxy.SetResponseWriter(w)
proxy.SetSourceRequest(r)
proxy.SetDestRequest(request)
return proxy
}
type ServiceProxy struct {
err error
serviceRequest func(request proto.Message) (proto.Message, error)
writer http.ResponseWriter
destRequest proto.Message
sourceRequest *http.Request
}
func (b *ServiceProxy) SetDestRequest(request proto.Message) {
b.destRequest = request
}
func (b *ServiceProxy) SetSourceRequest(request *http.Request) {
b.sourceRequest = request
}
func (b *ServiceProxy) SetServiceRequest(svcRequest func(request proto.Message) (proto.Message, error)) *ServiceProxy {
b.serviceRequest = svcRequest
return b
}
func (b *ServiceProxy) Call() {
b.writer.Header().Set("Content-Type", "application/json; charset=utf-8")
err := unmarshal(b.writer, b.sourceRequest, b.destRequest)
if err != nil {
return
}
resp, err := b.serviceRequest(b.destRequest)
if err != nil {
handleErrorResp(b.writer, err)
return
}
b.writer.WriteHeader(http.StatusOK)
json.NewEncoder(b.writer).Encode(resp)
}
func (b *ServiceProxy) SetResponseWriter(w http.ResponseWriter) {
b.writer = w
}