.NET Core未授权访问自定义错误处理问题排查与优化
解决方案
1. 直接访问Error/Error时无异常信息的问题
直接访问/Error/Error时,并没有触发任何异常,所以HttpContext.Features.Get<IExceptionHandlerFeature>()自然返回null,这是正常行为。你可以在Error方法里做场景区分:
- 异常触发的错误跳转:此时存在
IExceptionHandlerFeature,可获取异常详情 - 手动访问错误页面:此时无异常信息,返回通用提示即可
示例代码:
public IActionResult Error() { var exceptionFeature = HttpContext.Features.Get<IExceptionHandlerFeature>(); var errorViewModel = new ErrorViewModel(); if (exceptionFeature != null) { errorViewModel.ExceptionMessage = exceptionFeature.Error.Message; errorViewModel.StackTrace = exceptionFeature.Error.StackTrace; // 记录异常日志 _logger.LogError(exceptionFeature.Error, "未处理异常"); } else { // 手动访问场景的提示 errorViewModel.ExceptionMessage = "未检测到异常,这是直接访问的错误页面"; } return View(errorViewModel); }
2. 获取403/404等状态码错误的更多信息
要获取状态码错误的额外信息,需正确配置中间件,并利用ASP.NET Core提供的扩展Feature:
步骤1:配置中间件(Program.cs/Startup.cs)
确保中间件顺序正确,UseExceptionHandler和UseStatusCodePagesWithReExecute要放在UseRouting、UseAuthorization之前:
// .NET 6+ 顶级语句示例 var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllersWithViews(); var app = builder.Build(); // 异常捕获跳转 app.UseExceptionHandler("/Error/Error"); // 捕获状态码错误并转发到Error控制器 app.UseStatusCodePagesWithReExecute("/Error/Error", "?statusCode={0}"); app.UseRouting(); app.UseAuthorization(); app.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); app.Run();
步骤2:在ErrorController中获取更多信息
除状态码外,还可通过以下Feature获取额外数据:
IStatusCodeReExecuteFeature:获取原始请求的路径、查询字符串IAuthorizationFailureFeature:获取403授权失败的详细原因(如未满足的策略、权限要求)
示例代码:
public IActionResult Error(int? statusCode) { var errorViewModel = new ErrorViewModel { StatusCode = statusCode ?? HttpContext.Response.StatusCode }; // 获取原始请求信息 var reExecuteFeature = HttpContext.Features.Get<IStatusCodeReExecuteFeature>(); if (reExecuteFeature != null) { errorViewModel.OriginalPath = reExecuteFeature.OriginalPath; errorViewModel.OriginalQueryString = reExecuteFeature.OriginalQueryString; } // 获取403授权失败详情 if (errorViewModel.StatusCode == 403) { var authFailureFeature = HttpContext.Features.Get<IAuthorizationFailureFeature>(); if (authFailureFeature != null) { errorViewModel.AuthFailureReasons = authFailureFeature.Failure.FailedRequirements .Select(r => r.GetType().Name) .ToList(); } } // 获取异常信息(如果是异常触发的状态码错误) var exceptionFeature = HttpContext.Features.Get<IExceptionHandlerFeature>(); if (exceptionFeature != null) { errorViewModel.ExceptionMessage = exceptionFeature.Error.Message; _logger.LogError(exceptionFeature.Error, "异常触发状态码 {StatusCode}", errorViewModel.StatusCode); } else { _logger.LogWarning("状态码错误 {StatusCode},原始路径:{OriginalPath}", errorViewModel.StatusCode, errorViewModel.OriginalPath); } return View(errorViewModel); }
步骤3:ErrorViewModel示例
定义视图模型承载信息:
public class ErrorViewModel { public int StatusCode { get; set; } public string? ExceptionMessage { get; set; } public string? StackTrace { get; set; } public string? OriginalPath { get; set; } public string? OriginalQueryString { get; set; } public List<string>? AuthFailureReasons { get; set; } }
3. 日志记录注意事项
- 注入
ILogger<ErrorController>到控制器,日志需包含状态码、原始请求、异常栈等上下文信息 - 404错误记录原始路径,方便排查无效链接
- 403错误记录授权失败原因,辅助调整权限策略
内容的提问来源于stack exchange,提问作者Xiao Han
相关产品推荐
相关产品推荐

