ASP.NET Core MVC全局异常处理中间件无法跳转自定义错误页如何解决?
问题根因
- 你在修改请求路径前已经向响应流写入了JSON内容、设置了
application/json的响应类型,响应头已部分发送,后续修改请求路径的操作不会生效 - 修改
Request.Path后没有重新触发中间件管道执行新的路径匹配逻辑,不会自动路由到你配置的错误页接口/Action
方案1:调整现有自定义中间件逻辑
你需要调整执行顺序,区分API请求和页面请求,修改路径后重新触发管道即可:
public class ErrorHandlerMiddleware { private readonly RequestDelegate _next; public ErrorHandlerMiddleware(RequestDelegate next) { _next = next; } public async Task Invoke(HttpContext context) { // 避免错误页本身抛出异常导致无限循环 if (context.Request.Path.StartsWithSegments("/error")) { await _next(context); return; } try { await _next(context); } catch (Exception error) { var response = context.Response; // 先清除已经写入的响应内容和响应头 response.Clear(); // 根据异常类型设置状态码 switch (error) { case KeyNotFoundException e: response.StatusCode = (int)HttpStatusCode.NotFound; break; default: response.StatusCode = (int)HttpStatusCode.InternalServerError; break; } // 区分API请求和页面请求:如果是请求API接口返回JSON,否则跳转错误页 if (context.Request.ContentType == "application/json" || context.Request.Path.StartsWithSegments("/api")) { response.ContentType = "application/json"; var result = JsonSerializer.Serialize(new { message = error?.Message }); await response.WriteAsync(result); } else { // 修改请求路径,重新触发管道执行,路由到错误页 context.Request.Path = $"/error/{response.StatusCode}"; await _next(context); } } } }
注意:需要在Program.cs中把这个中间件注册到所有中间件的最开头,才能捕获全管道的异常。
方案2:使用ASP.NET Core内置错误处理组件(更推荐)
不用自行实现中间件,官方提供的组件已经覆盖了全局异常、状态码错误处理的需求,符合ASP.NET Core设计规范:
Program.cs配置
var builder = WebApplication.CreateBuilder(args); // 添加控制器和视图服务(MVC) builder.Services.AddControllersWithViews(); var app = builder.Build(); // 开发环境使用开发者异常页,生产环境使用自定义错误页 if (!app.Environment.IsDevelopment()) { // 全局异常处理 app.UseExceptionHandler("/error/500"); // 处理404等非异常类的状态码错误 app.UseStatusCodePagesWithReExecute("/error/{0}"); } else { app.UseDeveloperExceptionPage(); } app.UseStaticFiles(); app.UseRouting(); app.UseAuthorization(); app.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); app.Run();
ErrorController示例
public class ErrorController : Controller { [Route("/error/{code:int}")] public IActionResult Error(int code) { // 根据不同状态码返回对应错误页,也可以统一返回通用错误页 return code switch { 404 => View("NotFound"), 500 => View("InternalError"), _ => View("CommonError", code) }; } }
你只需要在Views/Error文件夹下创建对应的错误页视图即可,该方案同时覆盖了异常捕获、404等无异常的错误状态码处理场景。
内容的提问来源于stack exchange,提问作者Pilouni
相关产品推荐
相关产品推荐

