如何处理gRPC拦截器调用前发生的错误?
处理gRPC拦截器调用前的全局错误(如反序列化失败)
当gRPC请求出现反序列化失败这类前置错误时,拦截器不会被触发,框架会返回模糊的Unknown状态错误。以下是两种可行的全局处理方案:
方案1:增强自定义ASP.NET Core中间件
直接在ASP.NET管道中捕获并处理gRPC响应,既能记录日志,也能修改响应内容:
public class GrpcGlobalErrorMiddleware { private readonly RequestDelegate _next; private readonly ILogger<GrpcGlobalErrorMiddleware> _logger; public GrpcGlobalErrorMiddleware(RequestDelegate next, ILogger<GrpcGlobalErrorMiddleware> logger) { _next = next; _logger = logger; } public async Task InvokeAsync(HttpContext context) { // 先执行后续管道 await _next(context); // 判断是否是gRPC请求且响应有错误 if (context.Request.ContentType?.StartsWith("application/grpc") == true) { var statusCodeHeader = context.Response.Headers["grpc-status"].FirstOrDefault(); var statusMessageHeader = context.Response.Headers["grpc-message"].FirstOrDefault(); // 处理Unknown状态的反序列化错误 if (statusCodeHeader == "2" && string.IsNullOrEmpty(statusMessageHeader)) { // 记录详细日志 _logger.LogError("gRPC请求反序列化失败,请求路径:{Path}", context.Request.Path); // 替换默认错误消息 context.Response.Headers["grpc-message"] = "请求数据格式不符合契约,请检查字段类型"; } } } } // 注册中间件(要放在UseGrpc之前) app.UseMiddleware<GrpcGlobalErrorMiddleware>(); app.MapGrpcService<YourGrpcService>();
方案2:使用ASP.NET Core全局异常处理器(.NET 7+)
利用ASP.NET Core 7引入的IExceptionHandler接口,捕获框架抛出的RpcException并自定义处理:
public class GrpcExceptionHandler : IExceptionHandler { private readonly ILogger<GrpcExceptionHandler> _logger; public GrpcExceptionHandler(ILogger<GrpcExceptionHandler> logger) { _logger = logger; } public async ValueTask<bool> TryHandleAsync(HttpContext context, Exception exception, CancellationToken cancellationToken) { if (exception is RpcException rpcException) { // 判断是否是反序列化导致的Unknown错误 if (rpcException.StatusCode == StatusCode.Unknown && rpcException.Message.Contains("Exception was thrown by handler")) { _logger.LogError(exception, "gRPC请求反序列化失败,路径:{Path}", context.Request.Path); // 构建自定义错误响应 var metadata = new Metadata { { "grpc-status", ((int)StatusCode.InvalidArgument).ToString() }, { "grpc-message", "请求数据格式错误,请按照契约传递正确类型的字段" } }; // 修改响应头 foreach (var entry in metadata) { context.Response.Headers[entry.Key] = entry.Value; } context.Response.StatusCode = StatusCodes.Status200OK; // gRPC始终返回200 return true; } } return false; // 其他异常交给默认处理 } } // 注册服务 builder.Services.AddExceptionHandler<GrpcExceptionHandler>(); // 启用异常处理中间件(放在UseGrpc之前) app.UseExceptionHandler();
关键说明
- 反序列化错误发生在gRPC拦截器管道之前,因此无法通过Interceptor类处理,必须借助ASP.NET Core管道的更早阶段或全局异常处理机制。
- 两种方案都需要确保中间件/异常处理器注册在
UseGrpc或MapGrpcService之前,才能捕获到框架生成的响应。 - 修改
grpc-status可以将默认的Unknown改为更准确的InvalidArgument,让客户端更清晰地理解错误类型。
内容的提问来源于stack exchange,提问作者hollo
相关产品推荐
相关产品推荐

