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
- Variables
- func DefaultErrorRenderer(ctx context.Context, st *status.Status, w http.ResponseWriter)
- 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 HandlerOption
- type HttpTrailer
- func (*HttpTrailer) Descriptor() ([]byte, []int)deprecated
- func (x *HttpTrailer) GetCode() int32
- func (x *HttpTrailer) GetDetails() []*anypb.Any
- func (x *HttpTrailer) GetMessage() string
- func (x *HttpTrailer) GetMetadata() map[string]*TrailerValues
- func (*HttpTrailer) ProtoMessage()
- func (x *HttpTrailer) ProtoReflect() protoreflect.Message
- func (x *HttpTrailer) Reset()
- func (x *HttpTrailer) String() string
- type Mux
- type TrailerValues
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
const ( // Non-standard and experimental; uses the `jsonpb.Marshaler` by default. // Only unary calls are supported; streams with JSON encoding are not supported. // Use `encoding.RegisterCodec` to override the default encoder with a custom encoder. ApplicationJson = "application/json" )
Variables ¶
var File_httpgrpc_proto protoreflect.FileDescriptor
Functions ¶
func DefaultErrorRenderer ¶ added in v1.1.0
DefaultErrorRenderer translates the gRPC code in the given status to an HTTP error response. The following table shows how status codes are translated:
Canceled: * 502 Bad Gateway Unknown: 500 Internal Server Error InvalidArgument: 400 Bad Request DeadlineExceeded: * 504 Gateway Timeout NotFound: 404 Not Found AlreadyExists: 409 Conflict PermissionDenied: 403 Forbidden Unauthenticated: 401 Unauthorized ResourceExhausted: 429 Too Many Requests FailedPrecondition: 412 Precondition Failed Aborted: 409 Conflict OutOfRange: 422 Unprocessable Entity Unimplemented: 501 Not Implemented Internal: 500 Internal Server Error Unavailable: 503 Service Unavailable DataLoss: 500 Internal Server Error * If the gRPC status indicates Canceled or DeadlineExceeded and the given request context ALSO indicates a context error (meaning that the request was cancelled by the client), then a 499 Client Closed Request code is used instead.
If any other gRPC status code is observed, it would get translated into a 500 Internal Server Error.
Note that OK is absent from the mapping because the error renderer will never be called for a non-error status.
This function uses http.Error to render the computed code (and corresponding status text) to the given ResponseWriter.
func HandleMethod ¶
func HandleMethod(svr interface{}, serviceName string, desc *grpc.MethodDesc, unaryInt grpc.UnaryServerInterceptor, opts ...HandlerOption) 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, opts ...HandlerOption)
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, opts ...HandlerOption) 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 HandlerOption ¶ added in v1.1.0
type HandlerOption func(*handlerOpts)
HandlerOption is an option to customize some aspect of the HTTP handler behavior, such as rendering gRPC errors to HTTP responses.
func ErrorRenderer ¶ added in v1.1.0
func ErrorRenderer(errFunc func(reqCtx context.Context, st *status.Status, response http.ResponseWriter)) HandlerOption
ErrorRenderer returns a HandlerOption that will cause the handler to use the given function to render an error. It is only used for unary RPCs since streaming RPCs serialize a status message to the response trailer (in the HTTP body) instead.
The function should call methods on response in order to write an error response, including any response headers, the HTTP status code, and any response body.
If no such option is used, the handler will use DefaultErrorRenderer.
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 []*anypb.Any `protobuf:"bytes,4,rep,name=details,proto3" json:"details,omitempty"` // contains filtered or unexported fields }
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
deprecated
func (*HttpTrailer) Descriptor() ([]byte, []int)
Deprecated: Use HttpTrailer.ProtoReflect.Descriptor instead.
func (*HttpTrailer) GetCode ¶
func (x *HttpTrailer) GetCode() int32
func (*HttpTrailer) GetDetails ¶
func (x *HttpTrailer) GetDetails() []*anypb.Any
func (*HttpTrailer) GetMessage ¶
func (x *HttpTrailer) GetMessage() string
func (*HttpTrailer) GetMetadata ¶
func (x *HttpTrailer) GetMetadata() map[string]*TrailerValues
func (*HttpTrailer) ProtoMessage ¶
func (*HttpTrailer) ProtoMessage()
func (*HttpTrailer) ProtoReflect ¶ added in v1.1.0
func (x *HttpTrailer) ProtoReflect() protoreflect.Message
func (*HttpTrailer) Reset ¶
func (x *HttpTrailer) Reset()
func (*HttpTrailer) String ¶
func (x *HttpTrailer) String() string
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"` // contains filtered or unexported fields }
func (*TrailerValues) Descriptor
deprecated
func (*TrailerValues) Descriptor() ([]byte, []int)
Deprecated: Use TrailerValues.ProtoReflect.Descriptor instead.
func (*TrailerValues) GetValues ¶
func (x *TrailerValues) GetValues() []string
func (*TrailerValues) ProtoMessage ¶
func (*TrailerValues) ProtoMessage()
func (*TrailerValues) ProtoReflect ¶ added in v1.1.0
func (x *TrailerValues) ProtoReflect() protoreflect.Message
func (*TrailerValues) Reset ¶
func (x *TrailerValues) Reset()
func (*TrailerValues) String ¶
func (x *TrailerValues) String() string