5.2 KiB
Encoding
The gRPC API for sending and receiving is based upon messages. However, messages cannot be transmitted directly over a network; they must first be converted into bytes. This document describes how gRPC-Go converts messages into bytes and vice-versa for the purposes of network transmission.
Codecs (Serialization and Deserialization)
A Codec contains code to serialize a message into a byte slice (Marshal) and
deserialize a byte slice back into a message (Unmarshal). Codecs are
registered by name into a global registry maintained in the encoding package.
Implementing a Codec
A typical Codec will be implemented in its own package with an init function
that registers itself, and is imported anonymously. For example:
package proto
import "google.golang.org/grpc/encoding"
func init() {
encoding.RegisterCodec(protoCodec{})
}
// ... implementation of protoCodec ...
For an example, gRPC's implementation of the proto codec can be found in
encoding/proto.
Using a Codec
By default, gRPC registers and uses the "proto" codec, so it is not necessary to
do this in your own code to send and receive proto messages. To use another
Codec from a client or server:
package myclient
import _ "path/to/another/codec"
Codecs, by definition, must be symmetric, so the same desired Codec should
be registered in both client and server binaries.
On the client-side, to specify a Codec to use for message transmission, the
CallOption CallContentSubtype should be used as follows:
response, err := myclient.MyCall(ctx, request, grpc.CallContentSubtype("mycodec"))
As a reminder, all CallOptions may be converted into DialOptions that become
the default for all RPCs sent through a client using grpc.WithDefaultCallOptions:
myclient := grpc.Dial(ctx, target, grpc.WithDefaultCallOptions(grpc.CallContentSubtype("mycodec")))
When specified in either of these ways, messages will be encoded using this
codec and sent along with headers indicating the codec (content-type set to
application/grpc+<codec name>).
On the server-side, using a Codec is as simple as registering it into the
global registry (i.e. importing it). If a message is encoded with the content
sub-type supported by a registered Codec, it will be used automatically for
decoding the request and encoding the response. Otherwise, for
backward-compatibility reasons, gRPC will attempt to use the "proto" codec. In
an upcoming change (tracked in this
issue), such requests will be
rejected with status code Unimplemented instead.
Compressors (Compression and Decompression)
Sometimes, the resulting serialization of a message is not space-efficient, and it may be beneficial to compress this byte stream before transmitting it over the network. To facilitate this operation, gRPC supports a mechanism for performing compression and decompression.
A Compressor contains code to compress and decompress by wrapping io.Writers
and io.Readers, respectively. (The form of Compress and Decompress were
chosen to most closely match Go's standard package
implementations of compressors. Like
Codecs, Compressors are registered by name into a global registry maintained
in the encoding package.
Implementing a Compressor
A typical Compressor will be implemented in its own package with an init
function that registers itself, and is imported anonymously. For example:
package gzip
import "google.golang.org/grpc/encoding"
func init() {
encoding.RegisterCompressor(compressor{})
}
// ... implementation of compressor ...
An implementation of a gzip compressor can be found in
encoding/gzip.
Using a Compressor
By default, gRPC does not register or use any compressors. To use a
Compressor from a client or server:
package myclient
import _ "google.golang.org/grpc/encoding/gzip"
Compressors, by definition, must be symmetric, so the same desired
Compressor should be registered in both client and server binaries.
On the client-side, to specify a Compressor to use for message transmission,
the CallOption UseCompressor should be used as follows:
response, err := myclient.MyCall(ctx, request, grpc.UseCompressor("gzip"))
As a reminder, all CallOptions may be converted into DialOptions that become
the default for all RPCs sent through a client using grpc.WithDefaultCallOptions:
myclient := grpc.Dial(ctx, target, grpc.WithDefaultCallOptions(grpc.UseCompresor("gzip")))
When specified in either of these ways, messages will be compressed using this
compressor and sent along with headers indicating the compressor
(content-coding set to <compressor name>).
On the server-side, using a Compressor is as simple as registering it into the
global registry (i.e. importing it). If a message is compressed with the
content coding supported by a registered Compressor, it will be used
automatically for decompressing the request and compressing the response.
Otherwise, the request will be rejected with status code Unimplemented.