.NET 8全局异常处理器无法写入response.Body问题求助
全局异常处理器无法返回响应体问题
问题背景
我正在开发一组API,需要通过全局异常处理器统一处理未捕获异常,要求完成格式化并记录异常、返回标准化响应体两项功能。目前日志记录功能已实现,但无论用哪种方式将对象写入response.Body,通过Postman或其他工具调用API时都无法获取到响应体。
我能修改response.StatusCode并得到对应的状态码,但响应体始终为空。已经调整过中间件/异常处理器的调用顺序,排查后续中间件是否修改响应,结果一致;也尝试过Kestrel、IIS、Docker等不同宿主,问题依旧。
已尝试的三种实现方案
1. 自定义异常中间件
最初采用自定义中间件实现,但响应体无法返回:
public class ExceptionMiddleware { private RequestDelegate _next; private SecurityHeadersPolicy _policy; public ExceptionMiddleware(RequestDelegate next, SecurityHeadersPolicy policy) { _next = next; } public async Task Invoke(HttpContext context, ILogger logger) { try { await _next(context); } catch (Exception ex) { logger.LogError((int)CommonLogCode.UnhandledError, "An unhandled error occurred.", ex); context.Request.Headers.TryGetValue(HeaderConstants.TransactionIdKey, out var transactionId); context.Response.ContentType = "application/json"; context.Response.StatusCode = (int)HttpStatusCode.BadRequest; var response = new DeveloperMessageResponse() { ErrorCode = string.Format("{0:0000}", CommonLogCode.UnhandledError), ReferenceId = transactionId, DeveloperMessage = "An unhandled exception occurred.", DisplayMessage = "An unexpected error occurred." }; IHeaderDictionary headers = context.Response.Headers; foreach (var headerValuePair in _policy.SetHeaders) { headers[headerValuePair.Key] = headerValuePair.Value; } foreach (var header in _policy.RemoveHeaders) { headers.Remove(header); } await context.Response.WriteAsync(JsonSerializer.Serialize(response)); } } }
2. 自定义IExceptionHandler类
查阅资料得知.NET 8推荐实现IExceptionHandler,但问题依旧:
public class GlobalExceptionHandler : IExceptionHandler { private readonly ILogger _logger; public GlobalExceptionHandler(ILogger logger) { _logger = logger; } public async ValueTask<bool> TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken) { _logger.LogError((int)CommonLogCode.UnhandledError, "An unhandled error occurred.", exception); httpContext.Request.Headers.TryGetValue(HeaderConstants.TransactionIdKey, out var transactionId); httpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError; httpContext.Response.ContentType = "application/json"; IHeaderDictionary headers = httpContext.Response.Headers; var response = new DeveloperMessageResponse() { ErrorCode = string.Format("{0:0000}", (int)CommonLogCode.UnhandledError), ReferenceId = transactionId, DeveloperMessage = "An unhandled exception occurred.", DisplayMessage = "An unexpected error occurred." }; await httpContext.Response.WriteAsJsonAsync(JsonSerializer.Serialize(response)); return true; } }
3. app.UseExceptionHandler Lambda表达式(当前实现)
尝试了WriteAsJsonAsync、WriteAsync、Body.Write等多种写入方法,仍无法返回响应体:
app.UseExceptionHandler(exceptionHandlerApp => { exceptionHandlerApp.Run(async context => { var logger = app.Services.GetRequiredService<ILogger>(); var policy = securityPolicy.Build(); var exceptionHandlerFeature = context.Features.Get<IExceptionHandlerFeature>(); logger.LogError((int)CommonLogCode.UnhandledError, "An unhandled error occurred.", exceptionHandlerFeature?.Error); context.Request.Headers.TryGetValue(HeaderConstants.TransactionIdKey, out var transactionId); //context.Response.Clear(); context.Response.StatusCode = (int)HttpStatusCode.NotFound; context.Response.ContentType = "application/json"; IHeaderDictionary headers = context.Response.Headers; foreach (var headerValuePair in policy.SetHeaders) { headers[headerValuePair.Key] = headerValuePair.Value; } foreach (var header in policy.RemoveHeaders) { headers.Remove(header); } var response = new DeveloperMessageResponse() { ErrorCode = string.Format("{0:0000}", (int)CommonLogCode.UnhandledError), ReferenceId = transactionId, DeveloperMessage = "An unhandled exception occurred.", DisplayMessage = "An unexpected error occurred." }; //var responseBuffer = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(response)); //await context.Response.Body.WriteAsync(responseBuffer, 0, responseBuffer.Length); await context.Response.WriteAsJsonAsync(JsonSerializer.Serialize(response)); //await context.Response.CompleteAsync(); }); });
完整Program.cs代码
var builder = WebApplication.CreateBuilder(args); builder.WebHost.UseKestrel(options => { options.AddServerHeader = false; options.AllowResponseHeaderCompression = false; }); // Add services to the container. builder.Services.AddMvcCore().AddApiExplorer(); builder.Services.AddControllers() .AddJsonOptions(options => { options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); options.JsonSerializerOptions.PropertyNameCaseInsensitive = true; }); builder.Services.Configure<ForwardedHeadersOptions>(options => { options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto; }); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddHttpContextAccessor(); builder.Services.AddApiAndSwaggerVersioningconfigurations(); builder.Services.AddAutoMapperDependencies("UserAPI*.dll"); builder.Services.AddFrameworkDependencies(); builder.Services.AddApplicationDependencies("UserAPI*.dll"); //builder.Services.AddExceptionHandler<GlobalExceptionHandler>(); var app = builder.Build(); var securityPolicy = new SecurityHeadersBuilder().AddDefaultAPISecurePolicy(); //app.UseExceptionMiddleware(securityPolicy); app.UseForwardedHeaders(); //app.UseExceptionHandler(opt => { }); app.UseExceptionHandler(exceptionHandlerApp => { exceptionHandlerApp.Run(async context => { var logger = app.Services.GetRequiredService<ILogger>(); var policy = securityPolicy.Build(); var exceptionHandlerFeature = context.Features.Get<IExceptionHandlerFeature>(); logger.LogError((int)CommonLogCode.UnhandledError, "An unhandled error occurred.", exceptionHandlerFeature?.Error); context.Request.Headers.TryGetValue(HeaderConstants.TransactionIdKey, out var transactionId); //context.Response.Clear(); context.Response.StatusCode = (int)HttpStatusCode.NotFound; context.Response.ContentType = "application/json"; IHeaderDictionary headers = context.Response.Headers; foreach (var headerValuePair in policy.SetHeaders) { headers[headerValuePair.Key] = headerValuePair.Value; } foreach (var header in policy.RemoveHeaders) { headers.Remove(header); } var response = new DeveloperMessageResponse() { ErrorCode = string.Format("{0:0000}", (int)CommonLogCode.UnhandledError), ReferenceId = transactionId, DeveloperMessage = "An unhandled exception occurred.", DisplayMessage = "An unexpected error occurred." }; //var responseBuffer = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(response)); //await context.Response.Body.WriteAsync(responseBuffer, 0, responseBuffer.Length); await context.Response.WriteAsJsonAsync(JsonSerializer.Serialize(response)); //await context.Response.CompleteAsync(); }); }); app.UseResponseSecurityHeaderMiddleware(securityPolicy); if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } else { app.UseHsts(); } app.UseHttpMiddleware(); app.UsePerformanceTrackingMiddleware(); app.UseHttpsRedirection(); app.UseRouting(); app.UseAuthorization(); int suppressVersionsBelow = 0; int.TryParse(builder.Configuration[ConfigConstants.SuppressVersionsBelow], out suppressVersionsBelow); var versioningProvider = app.Services.GetRequiredService<IApiVersionDescriptionProvider>(); app.ConfigureSwaggerUI(versioningProvider, suppressVersionsBelow); app.MapControllers(); app.Run();
期望结果
希望返回以下格式的JSON响应体:
{ "ErrorCode": "0000", "ReferenceId": "请求中的TransactionId", "DeveloperMessage": "An unhandled exception occurred.", "DisplayMessage": "An unexpected error occurred." }
内容的提问来源于stack exchange,提问作者watts
相关产品推荐
相关产品推荐

