Documentation ¶
Overview ¶
Package httpgrpc contains code for using HTTP 1.1 for GRPC calls. This is intended only for environments where real GRPC is not possible or prohibitively expensive, like Google App Engine. It could possibly be used to perform GRPC operations from a browser, however no client implementation, other than a Go client, is provided.
For servers, RPC handlers will be invoked directly from an HTTP request, optionally transiting through a server interceptor. Importantly, this does not transform the request and then proxy it on loopback to the actual GRPC server. So GRPC service handlers are dispatched directly from HTTP server handlers.
Caveats ¶
There are couple of limitations when using this package:
- True bidi streams are not supported. The best that can be done are half-duplex bidi streams, where the client uploads its entire streaming request and then the server can reply with a streaming response. Interleaved reading and writing does not work with HTTP 1.1. (Even if there were clients that supported it, the Go HTTP server APIS do not -- once a server handler starts writing to the response body, the request body is closed and no more messages can be read from it).
- Client-side interceptors that interact with the *grpc.ClientConn, such as examining connection states or querying static method configs, will not work. No GRPC client connection is actually established and HTTP 1.1 calls will supply a nil *grpc.ClientConn to any interceptor.
Note that for environments like Google App Engine, which do not support streaming, use of streaming RPCs may result in high latency and high memory usage as entire streams must be buffered in memory. Use streams judiciously when inter-operating with App Engine.
This package does not attempt to block use of full-duplex streaming. So if HTTP 1.1 is used to invoke a bidi streaming method, the RPC will almost certainly fail because the server's sending of headers and the first response message will immediately close the request side for reading. So later attempts to read a request message will fail.
Anatomy of GRPC-over-HTTP ¶
A unary RPC is the simplest: the request will be a POST message and the request path will be the base URL's path (if any) plus "/service.name/method" (where service.name and method represent the fully-qualified proto service name and the method name for the unary method being invoked). Request metadata are used directly as HTTP request headers. The request payload is the binary-encoded form of the request proto, and the content-type is "application/x-protobuf". The response includes the best match for an HTTP status code based on the GRPC status code. But the response also includes a special response header, "X-GRPC-Status", that encodes the actual GRPC status code and message in a "code:message" string format. The response body is the binary-encoded form of the response proto, but will be empty when the GRPC status code is not "OK". If the RPC failed and the error includes details, they are attached via one or more headers named "X-GRPC-Details". If more than one error detail is associated with the status, there will be more than one header, and they will be added to the response in the same order as they appear in the server-side status. The value for the details header is a base64-encoding google.protobuf.Any message, which contains the error detail message. If the handler sends trailers, not just headers, they are encoded as HTTP 1.1 headers, but their names are prefixed with "X-GRPC-Trailer-". This allows clients to recover headers and trailers independently, as the server handler intended them.
Streaming RPCs are a bit more complex. Since the payloads can include multiple messages, the content type is not "application/x-protobuf". It is instead "application/x-httpgrpc-proto+v1". The actual request and response bodies consist of a sequence of length-delimited proto messages, each of which is binary encoded. The length delimiter is a 32-bit prefix that indicates the size of the subsequent message. Response sequences have a special final message that is encoded with a negative size (e.g. if the message size were 15, it would be written as -15 on the wire in the 32-bit prefix). The type of this special final message is always HttpTrailer, whereas the types of all other messages in the sequence are that of the method's request proto. The HttpTrailer final message indicates the final disposition of the stream (e.g. a GRPC status code and error details) as well as any trailing metadata. Because the status code is not encoded until the end of the response payload, the HTTP status code (which is the first line of the reply) will be 200 OK.
For clients that support streaming, client and server streams both work over HTTP 1.1. However, bidirectional streaming methods can only work if they are "half-duplex", where the client fully sends all request messages and then the server fully sends all response messages (e.g. the invocation timeline can have no interleaving/overlapping of request and response messages).
Index ¶
- Constants
- func HandleMethod(svr interface{}, serviceName string, desc *grpc.MethodDesc, ...) http.HandlerFunc
- func HandleServices(mux Mux, basePath string, reg grpchan.HandlerMap, ...)
- func HandleStream(svr interface{}, serviceName string, desc *grpc.StreamDesc, ...) http.HandlerFunc
- type Channel
- type HttpTrailer
- func (*HttpTrailer) Descriptor() ([]byte, []int)
- func (m *HttpTrailer) GetCode() int32
- func (m *HttpTrailer) GetDetails() []*any.Any
- func (m *HttpTrailer) GetMessage() string
- func (m *HttpTrailer) GetMetadata() map[string]*TrailerValues
- func (*HttpTrailer) ProtoMessage()
- func (m *HttpTrailer) Reset()
- func (m *HttpTrailer) String() string
- func (m *HttpTrailer) XXX_DiscardUnknown()
- func (m *HttpTrailer) XXX_Marshal(b []byte, deterministic bool) ([]byte, error)
- func (dst *HttpTrailer) XXX_Merge(src proto.Message)
- func (m *HttpTrailer) XXX_Size() int
- func (m *HttpTrailer) XXX_Unmarshal(b []byte) error
- type Mux
- type TrailerValues
- func (*TrailerValues) Descriptor() ([]byte, []int)
- func (m *TrailerValues) GetValues() []string
- func (*TrailerValues) ProtoMessage()
- func (m *TrailerValues) Reset()
- func (m *TrailerValues) String() string
- func (m *TrailerValues) XXX_DiscardUnknown()
- func (m *TrailerValues) XXX_Marshal(b []byte, deterministic bool) ([]byte, error)
- func (dst *TrailerValues) XXX_Merge(src proto.Message)
- func (m *TrailerValues) XXX_Size() int
- func (m *TrailerValues) XXX_Unmarshal(b []byte) error
Constants ¶
const ( UnaryRpcContentType_V1 = "application/x-protobuf" StreamRpcContentType_V1 = "application/x-httpgrpc-proto+v1" )
These are the content-types used for "version 1" (hopefully the only version ever?) of the gRPC-over-HTTP transport
Variables ¶
This section is empty.
Functions ¶
func HandleMethod ¶
func HandleMethod(svr interface{}, serviceName string, desc *grpc.MethodDesc, unaryInt grpc.UnaryServerInterceptor) http.HandlerFunc
HandleMethod returns an HTTP handler that will handle a unary RPC method by dispatching the given method on the given server.
func HandleServices ¶
func HandleServices(mux Mux, basePath string, reg grpchan.HandlerMap, unaryInt grpc.UnaryServerInterceptor, streamInt grpc.StreamServerInterceptor)
HandleServices uses the given mux to register handlers for all methods exposed by handlers registered in reg. They are registered using a path of "basePath/name.of.Service/Method". If non-nil interceptor(s) are provided then they will be used to intercept applicable RPCs before dispatch to the registered handler.
func HandleStream ¶
func HandleStream(svr interface{}, serviceName string, desc *grpc.StreamDesc, streamInt grpc.StreamServerInterceptor) http.HandlerFunc
HandleStream returns an HTTP handler that will handle a streaming RPC method by dispatching the given method on the given server.
Types ¶
type Channel ¶
type Channel struct { Transport http.RoundTripper BaseURL *url.URL }
Channel is used as a connection for GRPC requests issued over HTTP 1.1. The server endpoint is configured using the BaseURL field, and the Transport can also be configured. Both of those fields must be specified.
It implements version 1 of the GRPC-over-HTTP transport protocol.
func (*Channel) Invoke ¶
func (ch *Channel) Invoke(ctx context.Context, methodName string, req, resp interface{}, opts ...grpc.CallOption) error
Invoke satisfies the grpchan.Channel interface and supports sending unary RPCs via the in-process channel.
func (*Channel) NewStream ¶
func (ch *Channel) NewStream(ctx context.Context, desc *grpc.StreamDesc, methodName string, opts ...grpc.CallOption) (grpc.ClientStream, error)
NewStream satisfies the grpchan.Channel interface and supports sending streaming RPCs via the in-process channel.
type HttpTrailer ¶
type HttpTrailer struct { Metadata map[string]*TrailerValues `` /* 157-byte string literal not displayed */ Code int32 `protobuf:"varint,2,opt,name=code,proto3" json:"code,omitempty"` Message string `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"` Details []*any.Any `protobuf:"bytes,4,rep,name=details,proto3" json:"details,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` }
HttpTrailer is the last message sent in a streaming GRPC-over-HTTP call, to encode the GRPC status code and any trailer metadata. This message is only used in GRPC responses, not in requests.
func (*HttpTrailer) Descriptor ¶
func (*HttpTrailer) Descriptor() ([]byte, []int)
func (*HttpTrailer) GetCode ¶
func (m *HttpTrailer) GetCode() int32
func (*HttpTrailer) GetDetails ¶
func (m *HttpTrailer) GetDetails() []*any.Any
func (*HttpTrailer) GetMessage ¶
func (m *HttpTrailer) GetMessage() string
func (*HttpTrailer) GetMetadata ¶
func (m *HttpTrailer) GetMetadata() map[string]*TrailerValues
func (*HttpTrailer) ProtoMessage ¶
func (*HttpTrailer) ProtoMessage()
func (*HttpTrailer) Reset ¶
func (m *HttpTrailer) Reset()
func (*HttpTrailer) String ¶
func (m *HttpTrailer) String() string
func (*HttpTrailer) XXX_DiscardUnknown ¶
func (m *HttpTrailer) XXX_DiscardUnknown()
func (*HttpTrailer) XXX_Marshal ¶
func (m *HttpTrailer) XXX_Marshal(b []byte, deterministic bool) ([]byte, error)
func (*HttpTrailer) XXX_Merge ¶
func (dst *HttpTrailer) XXX_Merge(src proto.Message)
func (*HttpTrailer) XXX_Size ¶
func (m *HttpTrailer) XXX_Size() int
func (*HttpTrailer) XXX_Unmarshal ¶
func (m *HttpTrailer) XXX_Unmarshal(b []byte) error
type Mux ¶
type Mux func(pattern string, handler func(http.ResponseWriter, *http.Request))
Mux is a function that can register a gRPC-over-HTTP handler. This is used to register handlers in bulk for an RPC service. Its signature matches that of the HandleFunc method of the http.ServeMux type, and it also matches that of the http.HandleFunc function (for registering handlers with the default mux).
Callers can provide custom Mux functions that further decorate the handler (for example, adding authentication checks, logging, error handling, etc).
type TrailerValues ¶
type TrailerValues struct { Values []string `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` }
func (*TrailerValues) Descriptor ¶
func (*TrailerValues) Descriptor() ([]byte, []int)
func (*TrailerValues) GetValues ¶
func (m *TrailerValues) GetValues() []string
func (*TrailerValues) ProtoMessage ¶
func (*TrailerValues) ProtoMessage()
func (*TrailerValues) Reset ¶
func (m *TrailerValues) Reset()
func (*TrailerValues) String ¶
func (m *TrailerValues) String() string
func (*TrailerValues) XXX_DiscardUnknown ¶
func (m *TrailerValues) XXX_DiscardUnknown()
func (*TrailerValues) XXX_Marshal ¶
func (m *TrailerValues) XXX_Marshal(b []byte, deterministic bool) ([]byte, error)
func (*TrailerValues) XXX_Merge ¶
func (dst *TrailerValues) XXX_Merge(src proto.Message)
func (*TrailerValues) XXX_Size ¶
func (m *TrailerValues) XXX_Size() int
func (*TrailerValues) XXX_Unmarshal ¶
func (m *TrailerValues) XXX_Unmarshal(b []byte) error