ASP.NET Core异常中间件在.NET 5中返回404 JSON响应失败的解决方法
解决.NET5中ExceptionHandler中间件返回404 JSON响应失败的问题
这个问题我之前升级.NET5的时候也碰到过!根源在于.NET5对404状态码的处理逻辑做了调整,默认会触发请求重新执行的机制,干扰了你在异常处理中间件里的响应写入操作。
问题原因
在.NET5及后续版本中,当你把响应状态码设为404时,ASP.NET Core会自动添加IStatusCodeReExecuteFeature到请求特性集合中。这个特性会让框架尝试重新执行请求,去查找是否有匹配的端点或者静态资源。这就导致你还在写入JSON响应的时候,响应流被提前关闭了,所以HttpClient会抛出"Error while copying content to a stream"的错误。而像400这类状态码不会触发这个重新执行逻辑,所以能正常返回。
解决方案
方法一:清除状态码重执行特性(针对性解决自定义异常场景)
在你的异常处理中间件中,设置完404状态码后,移除IStatusCodeReExecuteFeature,阻止框架后续的自动处理逻辑,同时显式设置响应的Content-Type确保客户端识别为JSON:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.UseExceptionHandler(appBuilder => { appBuilder.Run(async context => { // 清除状态码重执行特性,阻止框架自动处理404 var statusCodeFeature = context.Features.Get<IStatusCodeReExecuteFeature>(); if (statusCodeFeature != null) { context.Features.Set<IStatusCodeReExecuteFeature>(null); } context.Response.StatusCode = (int)HttpStatusCode.NotFound; // 显式设置Content-Type为JSON格式 context.Response.ContentType = "application/json"; var responseContent = new { StatusCode = context.Response.StatusCode, Message = "Not found" }; await context.Response.WriteAsJsonAsync(responseContent); }); }); // 其他中间件配置(路由、端点等) app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); }
方法二:使用自定义状态码页面中间件(通用404处理)
如果你的应用需要统一处理所有404场景(包括未找到端点的情况,不只是自定义异常),可以结合UseExceptionHandler和UseStatusCodePages中间件,分工处理异常捕获和状态码响应:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { // 先捕获自定义异常并设置对应的状态码 app.UseExceptionHandler(appBuilder => { appBuilder.Run(async context => { var exceptionFeature = context.Features.Get<IExceptionHandlerPathFeature>(); if (exceptionFeature?.Error is NotFoundException) { context.Response.StatusCode = (int)HttpStatusCode.NotFound; } // 可添加其他异常的状态码映射逻辑 }); }); // 统一处理所有404响应,返回JSON格式内容 app.UseStatusCodePages(async context => { if (context.HttpContext.Response.StatusCode == (int)HttpStatusCode.NotFound) { context.HttpContext.Response.ContentType = "application/json"; var responseContent = new { StatusCode = 404, Message = "Not found" }; await context.HttpContext.Response.WriteAsJsonAsync(responseContent); } // 可添加其他状态码的响应逻辑 }); // 其他中间件配置 app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); }
注意事项
- 方法一更贴合你的场景,直接在异常处理中间件内部解决了404响应被干扰的问题,确保自定义
NotFoundException被正确处理为JSON格式的404响应。 - 一定要显式设置
ContentType为application/json,避免客户端无法正确解析响应内容。
内容的提问来源于stack exchange,提问作者Nick Prince
相关产品推荐
相关产品推荐

