gRPC를 사용하여 오류 처리
작성자: James Newton-King
이 문서에서는 오류 처리 및 gRPC에 대해 설명합니다.
- gRPC 상태 코드 및 오류 메시지를 사용하는 기본 제공 오류 처리 기능입니다.
- 풍부한 오류 처리를 사용하여 복잡하고 구조화된 오류 정보를 보냅니다.
기본 제공 오류 처리
gRPC 호출은 상태 코드를 사용하여 성공 또는 실패를 전달합니다. gRPC 호출이 성공적으로 완료되면 서버는 클라이언트에 OK
상태 반환합니다. 오류가 발생하면 gRPC는 다음을 반환합니다.
- 오류 상태 코드(예:
CANCELLED
또는UNAVAILABLE
. - 선택적 문자열 오류 메시지입니다.
오류 처리에 일반적으로 사용되는 형식은 다음과 같습니다.
StatusCode
: gRPC 상태 코드의 열거형입니다.OK
신호 성공; 다른 값은 실패입니다.Status
struct
: 문자열 오류 메시지와 선택적 문자열을 결합StatusCode
하는 값입니다. 오류 메시지는 발생한 작업에 대한 자세한 정보를 제공합니다.RpcException
: 값이 있는 예외 형식입니다Status
. 이 예외는 gRPC 서버 메서드에서 throw되고 gRPC 클라이언트에 의해 catch됩니다.
기본 제공 오류 처리는 상태 코드 및 문자열 설명만 지원합니다. 서버에서 클라이언트 로 복잡한 오류 정보를 보내려면 풍부한 오류 처리를 사용합니다.
서버 오류 throw
gRPC 서버 호출은 항상 상태 반환합니다. 메서드가 성공적으로 완료되면 서버가 자동으로 반환 OK
됩니다.
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));
}
}
}
앞의 코드가 하는 역할은 다음과 같습니다.
- 응답 메시지를 반환할 때 성공적으로 완료되는 단항
SayHello
메서드를 구현합니다. - 메서드가 완료되면 성공적으로 완료되는 서버 스트리밍
SayHelloStreaming
메서드를 구현합니다.
서버 오류 상태
gRPC 메서드는 예외를 throw하여 오류 상태 코드를 반환합니다. RpcException
서버에서 throw되면 해당 상태 코드 및 설명이 클라이언트에 반환됩니다.
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}" });
}
}
호출이 실패하지 RpcException
는 않지만 UNKNOWN
상태 코드와 일반 메시지를 Exception was thrown by handler
포함하는 throw된 예외 형식입니다.
Exception was thrown by handler
는 잠재적으로 중요한 정보가 노출되지 않도록 예외 메시지 대신 클라이언트로 전송됩니다. 개발 환경에서 보다 설명적인 오류 메시지를 보려면 구성 EnableDetailedErrors
합니다.
클라이언트 오류 처리
gRPC 클라이언트가 호출을 하면 응답에 액세스할 때 상태 코드의 유효성이 자동으로 검사됩니다. 예를 들어 단항 gRPC 호출을 기다리면 호출이 성공하면 서버에서 보낸 메시지가 반환되고 오류가 발생하면 throw됩니다 RpcException
. Catch RpcException
를 통해 클라이언트에서 오류를 처리합니다.
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);
}
앞의 코드가 하는 역할은 다음과 같습니다.
- 메서드에 대한 단항 gRPC 호출을 만듭니
SayHello
다. - 성공하면 응답 메시지를 콘솔에 씁니다.
- 오류에 대한 오류 세부 정보를 catch
RpcException
하고 씁니다.
오류 시나리오
오류는 오류 상태 코드 및 선택적 세부 정보 메시지로 표시됩니다RpcException
. RpcException
는 다음과 같은 여러 시나리오에서 throw됩니다.
- 서버에서 호출이 실패했고 서버가 코드에 상태 오류를 보냈습니다. 예를 들어 gRPC 클라이언트는 요청 메시지에서 필요한 데이터가 누락된 호출을 시작했고 서버는 상태 코드를 반환
INVALID_ARGUMENT
합니다. - gRPC를 호출할 때 클라이언트 내부에서 오류가 발생했습니다. 예를 들어 클라이언트가 gRPC를 호출하고 서버에 연결할 수 없으며 상태
UNAVAILABLE
오류가 발생합니다. - CancellationToken gRPC 호출에 전달된 호출이 취소됩니다. gRPC 호출이 중지되고 클라이언트가 상태
CANCELLED
오류를 throw합니다. - gRPC 호출이 구성된 기한을 초과합니다. gRPC 호출이 중지되고 클라이언트가 상태
DEADLINE_EXCEEDED
오류를 throw합니다.
풍부한 오류 처리
풍부한 오류 처리를 사용하면 복잡한 구조적 정보를 오류 메시지와 함께 보낼 수 있습니다. 예를 들어 잘못된 필드 이름 및 설명 목록을 반환하는 들어오는 메시지 필드의 유효성을 검사합니다. google.rpc.Status
오류 모델은 gRPC 앱 간에 복잡한 오류 정보를 보내는 데 자주 사용됩니다.
.NET의 gRPC는 패키지를 사용하여 Grpc.StatusProto
풍부한 오류 모델을 지원합니다. 이 패키지에는 서버에서 다양한 오류 모델을 만들고 클라이언트에서 읽는 메서드가 있습니다. 풍부한 오류 모델은 gRPC의 기본 제공 처리 기능을 기반으로 하며 병렬로 사용할 수 있습니다.
Important
오류는 헤더에 포함되며 응답의 총 헤더는 종종 8KB(8,192바이트)로 제한됩니다. 오류가 포함된 헤더가 8KB를 초과하지 않는지 확인합니다.
서버에서 다양한 오류 만들기
에서 다양한 오류가 생성 Google.Rpc.Status
됩니다. 이 형식은 Grpc.Core.Status
.
Google.Rpc.Status
에는 상태, 메시지 및 세부 정보 필드가 있습니다. 가장 중요한 필드는 값의 Any
반복 필드인 세부 정보입니다. 세부 정보는 복잡한 페이로드가 추가되는 위치입니다.
모든 메시지 유형을 페이로드로 사용할 수 있지만 표준 오류 페이로드 중 하나를 사용하는 것이 좋습니다.
BadRequest
PreconditionFailure
ErrorInfo
ResourceInfo
QuotaFailure
Grpc.StatusProto
에는 ToRpcException
오류로 변환 Google.Rpc.Status
할 도우미 메서드가 포함되어 있습니다. gRPC 서버 메서드에서 오류를 throw합니다.
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();
}
}
}
클라이언트에서 다양한 오류 읽기
클라이언트에서 catch된 RpcException
오류에서 다양한 오류를 읽습니다. 예외를 catch하고 제공된 도우미 메서드를 Grpc.StatusCode
사용하여 해당 Google.Rpc.Status
인스턴스를 가져옵니다.
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}");
}
}
}
앞의 코드가 하는 역할은 다음과 같습니다.
- catch하는 try/catch 내에서 gRPC 호출을 만듭니다
RpcException
. - 예외에서 풍부한 오류 모델을 가져오기 위한 호출
GetRpcStatus()
입니다. - 풍부한 오류에서 페이로드를
BadRequest
가져오기 위해 호출GetDetail<BadRequest>()
합니다.
추가 리소스
ASP.NET Core
피드백
https://aka.ms/ContentUserFeedback
출시 예정: 2024년 내내 콘텐츠에 대한 피드백 메커니즘으로 GitHub 문제를 단계적으로 폐지하고 이를 새로운 피드백 시스템으로 바꿀 예정입니다. 자세한 내용은 다음을 참조하세요.다음에 대한 사용자 의견 제출 및 보기