Komponent TsgcGRPCClient dostarcza gRPC do Delphi i C++Builder bez żadnego zewnętrznego środowiska uruchomieniowego. Jest częścią edycji sgcWebSockets Enterprise i działa w systemach Windows, macOS, Linux, iOS oraz Android. Ten przewodnik wyjaśnia, jak klient działa, jak go skonfigurować i jak wykonać każdy z czterech typów wywołań gRPC w Delphi.
Jak to działa
gRPC to komunikaty Protocol Buffers oprawione w ramki na HTTP/2. Każdy komunikat jest wysyłany jako ładunek z prefiksem długości w strumieniu HTTP/2, żądanie niesie nagłówki takie jak content-type: application/grpc oraz grpc-timeout, a końcowy status pojawia się jako zwiastuny (trailers) grpc-status i grpc-message.
sgcWebSockets dostarcza już kompletny stos HTTP/2, więc TsgcGRPCClient opiera się na transporcie TsgcHTTP2Client. Przekazujesz mu zserializowane bajty żądania, a on wykonuje opakowanie w ramki, obsługę nagłówków i terminów, otwiera strumień HTTP/2 oraz parsuje odpowiedź i zwiastuny z powrotem do typowanego TsgcGRPCResponse. Ponieważ klient operuje na surowych TBytes, możesz połączyć go z dowolną biblioteką Protocol Buffers, której już używasz.
Konfiguracja klienta
Kanał gRPC to połączenie HTTP/2. Utwórz TsgcHTTP2Client, wskaż mu host i port, a następnie przypisz go do właściwości Client komponentu gRPC. Dla TLS klient HTTP/2 używa OpenSSL lub Windows SChannel; dla lokalnego serwera bez szyfrowania (h2c) ustaw TLS na False.
uses
sgcHTTP2, sgcGRPC_Client, sgcGRPC_Classes, sgcGRPC_Types;
var
HTTP2: TsgcHTTP2Client;
GRPC: TsgcGRPCClient;
begin
HTTP2 := TsgcHTTP2Client.Create(nil);
HTTP2.Host := 'grpc.example.com';
HTTP2.Port := 443;
HTTP2.TLS := True; // False for a local h2c server
HTTP2.TLSOptions.IOHandler := iohOpenSSL; // or iohSChannel on Windows
GRPC := TsgcGRPCClient.Create(nil);
GRPC.Client := HTTP2;
end;
Konfiguracja kanału
Ustawienia obejmujące cały kanał znajdują się w ChannelOptions. Możesz włączyć kompresję gzip dla poszczególnych komunikatów, wybrać typ zawartości przesyłanej na łączu oraz podnieść limity rozmiaru komunikatu i metadanych.
// gzip-compress outgoing messages
GRPC.ChannelOptions.Compression := grpcGzip; // grpcNoCompression, grpcGzip, grpcDeflate, grpcSnappy
// application/grpc+proto (default) or application/grpc+json
GRPC.ChannelOptions.ContentType := grpcProto; // or grpcJSON
// raise the limits for large messages
GRPC.ChannelOptions.MaxMessageSize := 16 * 1024 * 1024;
GRPC.ChannelOptions.MaxMetadataSize := 64 * 1024;
Metadane i uwierzytelnianie
Niestandardowe nagłówki przesyłane są jako metadane gRPC. Dodaj je do DefaultMetadata, aby wysyłać je przy każdym wywołaniu, co jest typowym miejscem na token autoryzacyjny lub nagłówek śledzenia.
GRPC.DefaultMetadata.Add('authorization', 'Bearer eyJ...');
GRPC.DefaultMetadata.Add('x-api-key', 'my-api-key');
Terminy i anulowanie
Limit czasu dla pojedynczego wywołania jest wysyłany jako standardowy nagłówek grpc-timeout, dzięki czemu serwer może zrezygnować w tym samym momencie co klient. Trwające wywołanie strumieniowe można w dowolnej chwili zatrzymać za pomocą CancelCall, przekazując identyfikator strumienia zwrócony podczas jego otwierania.
Wywołania unarne
Wywołanie unarne wysyła jedno żądanie i otrzymuje jedną odpowiedź. Call blokuje do czasu nadejścia odpowiedzi i zwraca TsgcGRPCResponse z polami StatusCode, StatusMessage, surowymi bajtami Data (lub DataString) oraz Trailers.
var
oResponse: TsgcGRPCResponse;
begin
oResponse := GRPC.Call('helloworld.Greeter', 'SayHello', RequestBytes);
if oResponse.StatusCode = grpcOK then
Memo1.Text := oResponse.DataString
else
ShowMessage('gRPC error ' + oResponse.StatusMessage);
end;
Aby zachować responsywność interfejsu, użyj CallAsync. Zwraca on natychmiast i dostarcza odpowiedź poprzez zdarzenie OnGRPCResponse.
GRPC.OnGRPCResponse := GRPCResponse;
GRPC.CallAsync('helloworld.Greeter', 'SayHello', RequestBytes);
procedure TForm1.GRPCResponse(Sender: TObject; const Response: TsgcGRPCResponse);
begin
if Response.StatusCode = grpcOK then
Memo1.Text := Response.DataString;
end;
Strumieniowanie po stronie serwera
Przy strumieniowaniu po stronie serwera wysyłasz jedno żądanie, a serwer zwraca strumień komunikatów. Każdy komunikat wywołuje OnGRPCStreamMessage, a OnGRPCStreamEnd uruchamia się raz, z końcowym statusem.
GRPC.OnGRPCStreamMessage := GRPCStreamMessage;
GRPC.OnGRPCStreamEnd := GRPCStreamEnd;
GRPC.ServerStreamingCall('chat.Feed', 'Subscribe', RequestBytes);
procedure TForm1.GRPCStreamMessage(Sender: TObject; aStreamId: Integer;
const aData: TBytes);
begin
Memo1.Lines.Add(DecodeMessage(aData));
end;
Strumieniowanie po stronie klienta
Strumieniowanie po stronie klienta jest lustrzanym odbiciem: wysyłasz strumień komunikatów, a serwer odpowiada raz. Otwórz strumień, wyślij każdy komunikat, a następnie zamknij go, aby odczytać pojedynczą odpowiedź.
var
vStreamId: Integer;
oResponse: TsgcGRPCResponse;
begin
vStreamId := GRPC.OpenClientStream('upload.Service', 'Send');
GRPC.SendStreamMessage(vStreamId, ChunkBytes1);
GRPC.SendStreamMessage(vStreamId, ChunkBytes2);
oResponse := GRPC.CloseClientStream(vStreamId);
if oResponse.StatusCode = grpcOK then
ShowMessage('Upload accepted');
end;
Strumieniowanie dwukierunkowe
Strumieniowanie dwukierunkowe prowadzi wymianę w trybie pełnego dupleksu przez pojedynczy strumień HTTP/2: obie strony wysyłają, kiedy tylko chcą. Otwórz strumień, wysyłaj komunikaty według potrzeb, obsługuj przychodzące komunikaty w OnGRPCStreamMessage i zamknij go po zakończeniu.
var
vStreamId: Integer;
begin
vStreamId := GRPC.OpenBidiStream('chat.Room', 'Connect');
GRPC.SendBidiMessage(vStreamId, EncodeMessage('hello'));
// ... incoming messages arrive on OnGRPCStreamMessage ...
GRPC.CloseBidiStream(vStreamId);
end;
Kody statusu i obsługa błędów
Każda odpowiedź niesie typowany StatusCode od grpcOK przez standardowy zestaw gRPC (grpcNOT_FOUND, grpcUNAVAILABLE, grpcDEADLINE_EXCEEDED, grpcUNAUTHENTICATED i pozostałe). Dla wywołań asynchronicznych i strumieniowych OnGRPCError zgłasza status gRPC inny niż OK, a OnGRPCException zgłasza awarię transportu lub połączenia.
GRPC.OnGRPCError := GRPCError;
procedure TForm1.GRPCError(Sender: TObject; aStreamId: Integer;
aStatusCode: TsgcGRPCStatusCode; const aStatusMessage: string);
begin
Memo1.Lines.Add(Format('gRPC error %d: %s', [Ord(aStatusCode), aStatusMessage]));
end;
Automatyczne ponawianie prób
Klient może ponawiać za Ciebie nieudane wywołania. Włącz RetryPolicy, ustaw liczbę prób i opóźnienie wycofania, a także wypisz kody statusu, które powinny wyzwalać ponowienie. To typowa konfiguracja dla przejściowych awarii grpcUNAVAILABLE.
GRPC.RetryPolicy.Enabled := True;
GRPC.RetryPolicy.MaxAttempts := 4;
GRPC.RetryPolicy.InitialBackoff := 200; // ms
GRPC.RetryPolicy.BackoffMultiplier := 2.0;
GRPC.RetryPolicy.RetryableStatusCodes :=
GRPC.RetryPolicy.RetryableStatusCodes + [grpcUNAVAILABLE, grpcRESOURCE_EXHAUSTED];
Dla logiki przekrojowej, takiej jak logowanie czy odświeżanie tokena, dodaj wpis do łańcucha Interceptors, który oprawia każde wywołanie w jednym miejscu.
Co dalej
Na bazie tego generycznego klienta sgcWebSockets dostarcza typowane klienty dla usług gRPC Google Cloud (Pub/Sub, Speech-to-Text, Translation, Vision, Natural Language, Cloud Storage, BigQuery i Vertex AI), dzięki czemu wywołujesz metody wysokiego poziomu zamiast ręcznie składać protobufy. Gotowy do uruchomienia przykład znajduje się w Demos\21.GRPC\01.GRPC_Client, a pełną dokumentację znajdziesz na stronie produktu klienta gRPC.
Masz pytania lub potrzebujesz pomocy na początek? Skontaktuj się z nami. Otrzymasz odpowiedź od ludzi, którzy napisali ten kod.
