Obsługa błędów przy użyciu usługi gRPC
Uwaga
Nie jest to najnowsza wersja tego artykułu. Aby zapoznać się z bieżącą wersją, zobacz wersję tego artykułu platformy .NET 9.
Ważne
Te informacje odnoszą się do produktu w wersji wstępnej, który może zostać znacząco zmodyfikowany, zanim zostanie wydany komercyjnie. Firma Microsoft nie udziela żadnych gwarancji, jawnych lub domniemanych, w odniesieniu do informacji podanych w tym miejscu.
Aby zapoznać się z bieżącą wersją, zobacz wersję tego artykułu platformy .NET 9.
Autor: James Newton-King
W tym artykule omówiono obsługę błędów i gRPC:
- Wbudowane możliwości obsługi błędów przy użyciu kodów stanu gRPC i komunikatów o błędach.
- Wysyłanie złożonych, ustrukturyzowanych informacji o błędach przy użyciu rozbudowanej obsługi błędów.
Wbudowana obsługa błędów
Wywołania gRPC komunikują powodzenie lub niepowodzenie z kodem stanu. Po pomyślnym zakończeniu wywołania gRPC serwer zwraca OK
stan do klienta. Jeśli wystąpi błąd, funkcja gRPC zwraca:
- Kod stanu błędu, taki jak
CANCELLED
lubUNAVAILABLE
. - Opcjonalny komunikat o błędzie ciągu.
Typy często używane z obsługą błędów to:
StatusCode
: wyliczenie kodów stanu gRPC.OK
sygnalizuje powodzenie; inne wartości to niepowodzenie.Status
: Elementstruct
, który łączyStatusCode
opcjonalny komunikat o błędzie ciągu. Komunikat o błędzie zawiera dodatkowe szczegóły dotyczące tego, co się stało.RpcException
: typ wyjątku, który maStatus
wartość. Ten wyjątek jest zgłaszany w metodach serwera gRPC i przechwycony przez klientów gRPC.
Wbudowana obsługa błędów obsługuje tylko kod stanu i opis ciągu. Aby wysyłać złożone informacje o błędach z serwera do klienta, użyj rozbudowanej obsługi błędów.
Zgłaszanie błędów serwera
Wywołanie serwera gRPC zawsze zwraca stan. Serwer jest automatycznie zwracany OK
po pomyślnym zakończeniu metody.
public class GreeterService : GreeterBase
{
public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
{
return Task.FromResult(new HelloReply { Message = $"Hello {request.Name}" });
}
public override async Task SayHelloStreaming(HelloRequest request,
IServerStreamWriter<HelloReply> responseStream, ServerCallContext context)
{
for (var i = 0; i < 5; i++)
{
await responseStream.WriteAsync(new HelloReply { Message = $"Hello {request.Name} {i}" });
await Task.Delay(TimeSpan.FromSeconds(1));
}
}
}
Powyższy kod ma następujące działanie:
- Implementuje jednoargumentową
SayHello
metodę, która kończy się pomyślnie po zwracaniu komunikatu odpowiedzi. - Implementuje metodę przesyłania strumieniowego
SayHelloStreaming
serwera, która kończy się pomyślnie po zakończeniu metody.
Stan błędu serwera
Metody gRPC zwracają kod stanu błędu, zgłaszając wyjątek. Gdy obiekt RpcException
zostanie zgłoszony na serwerze, jego kod stanu i opis są zwracane do klienta:
public class GreeterService : GreeterBase
{
public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
{
if (string.IsNullOrEmpty(request.Name))
{
throw new RpcException(new Status(StatusCode.InvalidArgument, "Name is required."));
}
return Task.FromResult(new HelloReply { Message = $"Hello {request.Name}" });
}
}
Zgłaszane typy wyjątków, które nie RpcException
powodują również niepowodzenia wywołania, ale z UNKNOWN
kodem stanu i ogólnym komunikatem Exception was thrown by handler
.
Exception was thrown by handler
program jest wysyłany do klienta, a nie do komunikatu o wyjątku, aby zapobiec ujawnieniu potencjalnie poufnych informacji. Aby wyświetlić bardziej opisowy komunikat o błędzie w środowisku projektowym, skonfiguruj element EnableDetailedErrors
.
Obsługa błędów klienta
Gdy klient gRPC wykonuje wywołanie, kod stanu jest automatycznie weryfikowany podczas uzyskiwania dostępu do odpowiedzi. Na przykład oczekiwanie na jednoargumentowe wywołanie gRPC zwraca komunikat wysyłany przez serwer, jeśli wywołanie powiedzie się i zgłasza błąd RpcException
. Przechwyć RpcException
w celu obsługi błędów w kliencie:
var client = new Greet.GreeterClient(channel);
try
{
var response = await client.SayHelloAsync(new HelloRequest { Name = "World" });
Console.WriteLine("Greeting: " + response.Message);
}
catch (RpcException ex)
{
Console.WriteLine("Status code: " + ex.Status.StatusCode);
Console.WriteLine("Message: " + ex.Status.Detail);
}
Powyższy kod ma następujące działanie:
- Wykonuje jednoargumentowe wywołanie gRPC do
SayHello
metody . - Zapisuje komunikat odpowiedzi w konsoli, jeśli zakończy się pomyślnie.
- Przechwytuje
RpcException
i zapisuje szczegóły błędu dotyczące błędu.
Scenariusze błędów
Błędy są reprezentowane przez RpcException
kod stanu błędu i opcjonalny komunikat szczegółów. RpcException
jest zgłaszany w wielu scenariuszach:
- Wywołanie nie powiodło się na serwerze, a serwer wysłał kod stanu błędu. Na przykład klient gRPC uruchomił wywołanie, które nie zawiera wymaganych danych z komunikatu żądania, a serwer zwraca
INVALID_ARGUMENT
kod stanu. - Wystąpił błąd wewnątrz klienta podczas wykonywania wywołania gRPC. Na przykład klient wykonuje wywołanie gRPC, nie może nawiązać połączenia z serwerem i zgłasza błąd ze stanem
UNAVAILABLE
. - Przekazana CancellationToken do wywołania gRPC jest anulowana. Wywołanie gRPC zostało zatrzymane, a klient zgłasza błąd ze stanem
CANCELLED
. - Wywołanie gRPC przekracza skonfigurowany termin. Wywołanie gRPC zostało zatrzymane, a klient zgłasza błąd ze stanem
DEADLINE_EXCEEDED
.
Zaawansowana obsługa błędów
Zaawansowana obsługa błędów umożliwia wysyłanie złożonych, ustrukturyzowanych informacji z komunikatami o błędach. Na przykład weryfikacja przychodzących pól komunikatów, które zwracają listę nieprawidłowych nazw pól i opisów. google.rpc.Status
Model błędów jest często używany do wysyłania złożonych informacji o błędach między aplikacjami gRPC.
Usługa gRPC na platformie .NET obsługuje zaawansowany model błędów przy użyciu Grpc.StatusProto
pakietu. Ten pakiet zawiera metody tworzenia zaawansowanych modeli błędów na serwerze i odczytywania ich przez klienta. Bogaty model błędów opiera się na wbudowanych możliwościach obsługi gRPC i mogą być używane obok siebie.
Ważne
Błędy są uwzględniane w nagłówkach, a łączna liczba nagłówków w odpowiedziach jest często ograniczona do 8 KB (8192 bajtów). Upewnij się, że nagłówki zawierające błędy nie przekraczają 8 KB.
Tworzenie rozbudowanych błędów na serwerze
Rozbudowane błędy są tworzone na podstawie Google.Rpc.Status
elementu . Ten typ różni się od .Grpc.Core.Status
Google.Rpc.Status
zawiera pola stanu, komunikatu i szczegółów. Najważniejsze pole to szczegóły, czyli powtarzające się pole Any
wartości. Szczegóły to miejsce, w którym dodawane są złożone ładunki.
Mimo że dowolny typ komunikatu może być używany jako ładunek, zaleca się użycie jednego ze standardowych ładunków błędów:
BadRequest
PreconditionFailure
ErrorInfo
ResourceInfo
QuotaFailure
Grpc.StatusProto
ToRpcException
zawiera metodę pomocnika, która ma być konwertowana Google.Rpc.Status
na błąd. Wyrzuć błąd z metody serwera gRPC:
public class GreeterService : Greeter.GreeterBase
{
public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
{
ArgumentNotNullOrEmpty(request.Name);
return Task.FromResult(new HelloReply { Message = "Hello " + request.Name });
}
public static void ArgumentNotNullOrEmpty(string value, [CallerArgumentExpression(nameof(value))] string? paramName = null)
{
if (string.IsNullOrEmpty(value))
{
var status = new Google.Rpc.Status
{
Code = (int)Code.InvalidArgument,
Message = "Bad request",
Details =
{
Any.Pack(new BadRequest
{
FieldViolations =
{
new BadRequest.Types.FieldViolation { Field = paramName, Description = "Value is null or empty" }
}
})
}
};
throw status.ToRpcException();
}
}
}
Odczytywanie rozbudowanych błędów przez klienta
Rozbudowane błędy są odczytywane z przechwyconego RpcException
w kliencie. Przechwyć wyjątek i użyj metod pomocnika udostępnianych przez Grpc.StatusCode
program , aby uzyskać jego Google.Rpc.Status
wystąpienie:
var client = new Greet.GreeterClient(channel);
try
{
var reply = await client.SayHelloAsync(new HelloRequest { Name = name });
Console.WriteLine("Greeting: " + reply.Message);
}
catch (RpcException ex)
{
Console.WriteLine($"Server error: {ex.Status.Detail}");
var badRequest = ex.GetRpcStatus()?.GetDetail<BadRequest>();
if (badRequest != null)
{
foreach (var fieldViolation in badRequest.FieldViolations)
{
Console.WriteLine($"Field: {fieldViolation.Field}");
Console.WriteLine($"Description: {fieldViolation.Description}");
}
}
}
Powyższy kod ma następujące działanie:
- Wykonuje wywołanie gRPC wewnątrz try/catch, które przechwytuje
RpcException
. - Wywołuje
GetRpcStatus()
metodę próby pobrania zaawansowanego modelu błędów z wyjątku. - Wywołania
GetDetail<BadRequest>()
próby pobraniaBadRequest
ładunku z zaawansowanego błędu.