处理 ASP.NET Core 中的错误

作者:Kirk LarkinTom DykstraSteve Smith

本文介绍了处理 ASP.NET Core Web 应用中常见错误的一些方法。 有关 Web API,请参阅 处理 ASP.NET Core Web API 中的错误

查看或下载示例代码。 (下载方法。)在测试示例应用时,F12 浏览器开发人员工具上的网络选项卡非常有用。

开发人员异常页

“开发人员异常”页显示未经处理的请求异常的详细信息。 ASP.NET Core 模板会生成以下代码:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}

当应用在开发环境中运行时,前面突出显示的代码启用开发人员异常页。

这些模板将 UseDeveloperExceptionPage 置于中间件管道的前面部分,以便它能够捕获随后中间件中抛出的未经处理的异常。

仅当应用程序在开发环境中运行时,前面的代码才启用开发人员异常页。 当应用在生产环境中运行时,不应公开显示详细的异常信息。 有关配置环境的详细信息,请参阅 在 ASP.NET Core 中使用多个环境

开发人员异常页可能包括关于异常和请求的以下信息:

  • 堆栈跟踪
  • 查询字符串参数(如果有)
  • Cookie(如果有)
  • 标头

不保证开发人员异常页会提供任何信息。 使用日志记录获取完整的错误信息。

异常处理程序页

若要为生产环境配置自定义错误处理页,请调用 UseExceptionHandler。 此异常处理中间件:

  • 捕获并记录未经处理的异常。
  • 使用指示的路径在备用管道中重新执行请求。 如果响应已启动,则不会重新执行请求。 模板生成的代码使用 /Error 路径重新执行请求。

警告

如果备用管道引发一个自身的异常,则异常处理中间件会重新引发原始异常。

在下面的示例中,UseExceptionHandler 在非开发环境中添加异常处理中间件:

if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

Razor Pages 应用模板在 Pages 文件夹中提供了一个“错误”页面 (.cshtml) 和 PageModel 类 (ErrorModel)。 对于 MVC 应用,项目模板包括 Error 操作方法和 Home 控制器的错误视图。

异常处理中间件使用原始 HTTP 方法重新执行请求。 如果错误处理程序终结点限制为一组特定的 HTTP 方法,那么只会对这些 HTTP 方法运行。 例如,使用 [HttpGet] 属性的 MVC 控制器操作仅对 GET 请求运行。 若要确保所有请求都到达自定义错误处理页,请不要将它们限制为一组特定的 HTTP 方法。

根据原始 HTTP 方法以不同方式处理异常:

  • 对于 Razor Pages,创建多个处理程序方法。 例如,使用 OnGet 处理 GET 异常,使用 OnPost 处理 POST 异常。
  • 对于 MVC,请将 HTTP 谓词属性应用于多个操作。 例如,使用 [HttpGet] 处理 GET 异常,使用 [HttpPost] 处理 POST 异常。

若要允许未经身份验证的用户查看自定义错误处理页,请确保它支持匿名访问。

访问异常

使用 IExceptionHandlerPathFeature 访问错误处理程序中的异常和原始请求路径。 以下代码将 ExceptionMessage 添加到由 ASP.NET Core 模板生成的默认 Pages/Error.cshtml.cs:

[ResponseCache(Duration=0, Location=ResponseCacheLocation.None, NoStore=true)]
[IgnoreAntiforgeryToken]
public class ErrorModel : PageModel
{
    public string RequestId { get; set; }
    public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
    public string ExceptionMessage { get; set; }
    private readonly ILogger<ErrorModel> _logger;

    public ErrorModel(ILogger<ErrorModel> logger)
    {
        _logger = logger;
    }

    public void OnGet()
    {
        RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;

        var exceptionHandlerPathFeature =
        HttpContext.Features.Get<IExceptionHandlerPathFeature>();
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
        {
            ExceptionMessage = "File error thrown";
            _logger.LogError(ExceptionMessage);
        }
        if (exceptionHandlerPathFeature?.Path == "/index")
        {
            ExceptionMessage += " from home page";
        }
    }
}

警告

请勿向客户端提供敏感错误信息。 提供服务的错误是一种安全风险。

若要在示例应用中测试异常,请执行以下操作:

  • 将环境设置为生产环境。
  • Program.cs 中的 webBuilder.UseStartup<Startup>(); 删除注释。
  • 在主页上选择“触发异常”。

异常处理程序 lambda

自定义异常处理程序页的替代方法是向 UseExceptionHandler 提供 lambda。 使用 lambda,可以在返回响应前访问错误。

以下代码使用 lambda 处理异常:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler(errorApp =>
        {
            errorApp.Run(async context =>
            {
                context.Response.StatusCode = (int) HttpStatusCode.InternalServerError;;
                context.Response.ContentType = "text/html";

                await context.Response.WriteAsync("<html lang=\"en\"><body>\r\n");
                await context.Response.WriteAsync("ERROR!<br><br>\r\n");

                var exceptionHandlerPathFeature =
                    context.Features.Get<IExceptionHandlerPathFeature>();

                if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
                {
                    await context.Response.WriteAsync(
                                              "File error thrown!<br><br>\r\n");
                }

                await context.Response.WriteAsync(
                                              "<a href=\"/\">Home</a><br>\r\n");
                await context.Response.WriteAsync("</body></html>\r\n");
                await context.Response.WriteAsync(new string(' ', 512)); 
            });
        });
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}

警告

不要向客户端提供来自 IExceptionHandlerFeatureIExceptionHandlerPathFeature 的敏感错误信息。 提供服务的错误是一种安全风险。

若要在示例应用中测试异常处理 lambda:

  • 将环境设置为生产环境。
  • Program.cs 中的 webBuilder.UseStartup<StartupLambda>(); 删除注释。
  • 在主页上选择“触发异常”。

UseStatusCodePages

默认情况下,ASP.NET Core 应用不会为 HTTP 错误状态代码(如“404 - 未找到”)提供状态代码页。 当应用遇到没有正文的 HTTP 400-599 错误状态代码时,它将返回状态代码和空响应正文。 若要提供状态代码页,请使用状态代码页中间件。 若要启用常见错误状态代码的默认纯文本处理程序,请在 Startup.Configure 方法中调用 UseStatusCodePages

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseStatusCodePages();

    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}

在请求处理中间件之前调用 UseStatusCodePages。 例如,在静态文件中间件和端点中间件之前调用 UseStatusCodePages

未使用 UseStatusCodePages 时,导航到没有终结点的 URL 会返回一条与浏览器相关的错误消息,指示找不到终结点。 例如,导航到 Home/Privacy2。 调用 UseStatusCodePages 时,浏览器返回:

Status Code: 404; Not Found

UseStatusCodePages 通常不在生产中使用,因为它返回对用户没有用的消息。

若要在示例应用中测试 UseStatusCodePages

  • 将环境设置为生产环境。
  • Program.cs 中的 webBuilder.UseStartup<StartupUseStatusCodePages>(); 删除注释。
  • 选择主页上的链接。

备注

状态代码页中间件不捕获异常。 若要提供自定义错误处理页,请使用异常处理程序页

包含格式字符串的 UseStatusCodePages

若要自定义响应内容类型和文本,请利用需要使用内容类型和格式字符串的 UseStatusCodePages 重载:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseStatusCodePages(
        "text/plain", "Status code page, status code: {0}");

    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}

在前面的代码中,{0} 是错误代码的占位符。

具有格式字符串的 UseStatusCodePages 通常不在生产环境中使用,因为它返回对用户没有用的消息。

若要在示例应用中测试 UseStatusCodePages,请从 Program.cs 中的 webBuilder.UseStartup<StartupFormat>(); 删除注释。

包含 lambda 的 UseStatusCodePages

若要指定自定义错误处理和响应写入代码,请利用需要使用 lambda 表达式的 UseStatusCodePages 重载:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseStatusCodePages(async context =>
    {
        context.HttpContext.Response.ContentType = "text/plain";

        await context.HttpContext.Response.WriteAsync(
            "Status code page, status code: " +
            context.HttpContext.Response.StatusCode);
    });

    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}

使用 lambda 的 UseStatusCodePages 通常不在生产中使用,因为它返回对用户没有用的消息。

若要在示例应用中测试 UseStatusCodePages,请从 Program.cs 中的 webBuilder.UseStartup<StartupStatusLambda>(); 删除注释。

UseStatusCodePagesWithRedirects

UseStatusCodePagesWithRedirects 扩展方法:

  • 向客户端发送“302 - 已找到”状态代码。
  • 将客户端重定向到 URL 模板中提供的错误处理终结点。 错误处理终结点通常会显示错误信息并返回 HTTP 200。
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseStatusCodePagesWithRedirects("/MyStatusCode?code={0}");

    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}

URL 模板可能会包括状态代码的 {0} 占位符,如前面的代码中所示。 如果 URL 模板以波形符 ~(代字号)开头,则 ~ 会替换为应用的 PathBase。 在应用中指定终结点时,请为终结点创建 MVC 视图或 Razor 页面。 有关 Razor Pages 示例,请参阅示例应用中的 Pages/MyStatusCode.cshtml

使用此方法通常是当应用:

  • 应将客户端重定向到不同的终结点(通常在不同的应用处理错误的情况下)。 对于 Web 应用,客户端的浏览器地址栏反映重定向终结点。
  • 不应保留原始状态代码并通过初始重定向响应返回该代码。

若要在示例应用中测试 UseStatusCodePages,请从 Program.cs 中的 webBuilder.UseStartup<StartupSCredirect>(); 删除注释。

UseStatusCodePagesWithReExecute

UseStatusCodePagesWithReExecute 扩展方法:

  • 向客户端返回原始状态代码。
  • 通过使用备用路径重新执行请求管道,从而生成响应正文。
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseStatusCodePagesWithReExecute("/MyStatusCode2", "?code={0}");

    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}

如果在应用中指定终结点,请为终结点创建 MVC 视图或 Razor 页面。 确保将 UseStatusCodePagesWithReExecute 放置在 UseRouting 之前,以便可以将请求重新路由到状态页。 有关 Razor Pages 示例,请参阅示例应用中的 Pages/MyStatusCode2.cshtml

使用此方法通常是当应用应:

  • 处理请求,但不重定向到不同终结点。 对于 Web 应用,客户端的浏览器地址栏反映最初请求的终结点。
  • 保留原始状态代码并通过响应返回该代码。

URL 模板和查询字符串模板可能包括状态代码的占位符 {0}。 URL 模板必须以 / 开头。

错误处理终结点可以获取生成错误的原始 URL,如下面的示例所示:

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public class MyStatusCode2Model : PageModel
{
    public string RequestId { get; set; }
    public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);

    public string ErrorStatusCode { get; set; }

    public string OriginalURL { get; set; }
    public bool ShowOriginalURL => !string.IsNullOrEmpty(OriginalURL);

    public void OnGet(string code)
    {
        RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
        ErrorStatusCode = code;

        var statusCodeReExecuteFeature = HttpContext.Features.Get<
                                               IStatusCodeReExecuteFeature>();
        if (statusCodeReExecuteFeature != null)
        {
            OriginalURL =
                statusCodeReExecuteFeature.OriginalPathBase
                + statusCodeReExecuteFeature.OriginalPath
                + statusCodeReExecuteFeature.OriginalQueryString;
        }
    }
}

有关 Razor Pages 示例,请参阅示例应用中的 Pages/MyStatusCode2.cshtml

若要在示例应用中测试 UseStatusCodePages,请从 Program.cs 中的 webBuilder.UseStartup<StartupSCreX>(); 删除注释。

禁用状态代码页

若要禁用 MVC 控制器或操作方法的状态代码页,请使用 [SkipStatusCodePages] 特性。

若要禁用 Razor Pages 处理程序方法或 MVC 控制器中的特定请求的状态代码页,请使用 IStatusCodePagesFeature

public void OnGet()
{
    // using Microsoft.AspNetCore.Diagnostics;
    var statusCodePagesFeature = HttpContext.Features.Get<IStatusCodePagesFeature>();

    if (statusCodePagesFeature != null)
    {
        statusCodePagesFeature.Enabled = false;
    }
}

异常处理代码

异常处理页中的代码可能也会引发异常。 应彻底测试生产错误页面,并格外小心,避免引发其自己的异常。

响应头

在响应头发送后:

  • 应用无法更改响应的状态代码。
  • 任何异常页或处理程序都无法运行。 必须完成响应或中止连接。

服务器异常处理

除了应用中的异常处理逻辑外,HTTP 服务器实现还能处理一些异常。 如果服务器在发送响应标头之前捕获到异常,服务器将发送不包含响应正文的 500 - Internal Server Error 响应。 如果服务器在发送响应标头后捕获到异常,服务器会关闭连接。 应用程序无法处理的请求将由服务器进行处理。 当服务器处理请求时,发生的任何异常都将由服务器的异常处理进行处理。 应用的自定义错误页面、异常处理中间件和筛选器都不会影响此行为。

启动异常处理

应用程序启动期间发生的异常仅可在承载层进行处理。 可以将主机配置为,捕获启动错误捕获详细错误

仅当错误在主机地址/端口绑定后出现时,托管层才能显示捕获的启动错误的错误页。 如果绑定失败:

  • 托管层将记录关键异常。
  • dotnet 进程崩溃。
  • 不会在 HTTP 服务器为 Kestrel 时显示任何错误页。

IIS(或 Azure 应用服务)或 IIS Express 上运行应用时,如果无法启动进程,ASP.NET Core 模块将返回“502.5 - 进程失败”。 有关详细信息,请参阅 对 Azure 应用服务和 IIS 上的 ASP.NET Core 进行故障排除

数据库错误页

数据库开发人员页面异常筛选器 AddDatabaseDeveloperPageExceptionFilter 捕获可以使用 Entity Framework Core 迁移解决的与数据库相关的异常。 当这些异常出现时,便会生成 HTML 响应,其中包含用于解决问题的可能操作的详细信息。 仅在开发环境中启用此页。 在指定个人用户帐户时,ASP.NET Core Razor Pages 模板生成以下代码:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(
            Configuration.GetConnectionString("DefaultConnection")));
    services.AddDatabaseDeveloperPageExceptionFilter();
    services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
        .AddEntityFrameworkStores<ApplicationDbContext>();
    services.AddRazorPages();
}

异常筛选器

在 MVC 应用中,可以全局配置异常筛选器,也可以为每个控制器或每个操作单独配置。 在 Razor Pages 应用中,可以全局配置异常筛选器,也可以为每个页面模型单独配置。 这些筛选器处理在执行控制器操作或其他筛选器时出现的任何未处理的异常。 有关详细信息,请参阅 ASP.NET Core 中的筛选器

异常筛选器适合捕获 MVC 操作内发生的异常,但它们不如内置异常处理中间件 UseExceptionHandler 灵活。 我们建议使用 UseExceptionHandler,除非你需要根据选择的 MVC 操作以不同的方式执行错误处理。

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}

模型状态错误

若要了解如何处理模型状态错误,请参阅模型绑定模型验证

其他资源

作者:Tom DykstraSteve Smith

本文介绍了处理 ASP.NET Core Web 应用中常见错误的一些方法。 有关 Web API,请参阅 处理 ASP.NET Core Web API 中的错误

查看或下载示例代码。 (下载方法。)

开发人员异常页

开发人员异常页显示请求异常的详细信息。 ASP.NET Core 模板会生成以下代码:

if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

当应用在开发环境中运行时,前面的代码启用开发人员异常页。

模板将 UseDeveloperExceptionPage 放在任何中间件之前,以便捕获后面的中间件中的异常。

仅当应用程序在开发环境中运行时,前面的代码才启用开发人员异常页。 当应用在生产环境中运行时,不应公开显示详细的异常信息。 有关配置环境的详细信息,请参阅 在 ASP.NET Core 中使用多个环境

开发人员异常页包括关于异常和请求的以下信息:

  • 堆栈跟踪
  • 查询字符串参数(如果有)
  • Cookie(如果有)
  • 标头

异常处理程序页

若要为生产环境配置自定义错误处理页,请使用异常处理中间件。 中间件:

  • 捕获并记录异常。
  • 在备用管道中为指定的页或控制器重新执行请求。 如果响应已启动,则不会重新执行请求。 模板生成的代码将请求重新执行到 /Error

在下面的示例中,UseExceptionHandler 在非开发环境中添加异常处理中间件:

if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

Razor Pages 应用模板在 Pages 文件夹中提供了一个“错误”页面 (.cshtml) 和 PageModel 类 (ErrorModel)。 对于 MVC 应用,项目模板包括错误操作方法和 Home 控制器的错误视图。

不要使用 HTTP 方法属性(如 HttpGet)标记错误处理程序操作方法。 显式谓词可阻止某些请求访问方法。 如果未经身份验证的用户应看到错误视图,则允许匿名访问该方法。

访问异常

使用 IExceptionHandlerPathFeature 访问错误处理程序控制器或页中的异常和原始请求路径:

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public class ErrorModel : PageModel
{
    public string RequestId { get; set; }
    public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
    public string ExceptionMessage { get; set; }

    public void OnGet()
    {
        RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;

        var exceptionHandlerPathFeature =
            HttpContext.Features.Get<IExceptionHandlerPathFeature>();
        if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
        {
            ExceptionMessage = "File error thrown";
        }
        if (exceptionHandlerPathFeature?.Path == "/index")
        {
            ExceptionMessage += " from home page";
        }
    }
}

警告

请勿向客户端提供敏感错误信息。 提供服务的错误是一种安全风险。

若要触发前面的异常处理页,请将环境设置为生产环境并强制引发异常。

异常处理程序 lambda

自定义异常处理程序页的替代方法是向 UseExceptionHandler 提供 lambda。 使用 lambda,可以在返回响应前访问错误。

下面的示例展示了如何使用 lambda 进行异常处理:

if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}
else
{
   app.UseExceptionHandler(errorApp =>
   {
        errorApp.Run(async context =>
        {
            context.Response.StatusCode = (int) HttpStatusCode.InternalServerError;
            context.Response.ContentType = "text/html";

            await context.Response.WriteAsync("<html lang=\"en\"><body>\r\n");
            await context.Response.WriteAsync("ERROR!<br><br>\r\n");

            var exceptionHandlerPathFeature = 
                context.Features.Get<IExceptionHandlerPathFeature>();

            if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
            {
                await context.Response.WriteAsync("File error thrown!<br><br>\r\n");
            }

            await context.Response.WriteAsync("<a href=\"/\">Home</a><br>\r\n");
            await context.Response.WriteAsync("</body></html>\r\n");
            await context.Response.WriteAsync(new string(' ', 512)); // IE padding
        });
    });
    app.UseHsts();
}

在前面的代码中,添加了 await context.Response.WriteAsync(new string(' ', 512));,以便 Internet Explorer 浏览器显示相应的错误消息,而非显示 IE 错误消息。 有关详细信息,请参阅此 GitHub 问题

警告

不要向客户端提供来自 IExceptionHandlerFeatureIExceptionHandlerPathFeature 的敏感错误信息。 提供服务的错误是一种安全风险。

若要在示例应用中查看异常处理 lambda 的结果,请使用 ProdEnvironmentErrorHandlerLambda 预处理器指令,并选择主页上的“触发异常”。

UseStatusCodePages

默认情况下,ASP.NET Core 应用不会为 HTTP 状态代码(如“404 - 未找到”)提供状态代码页。 应用返回状态代码和空响应正文。 若要提供状态代码页,请使用状态代码页中间件。

此中间件是通过 Microsoft.AspNetCore.Diagnostics 包提供。

若要启用常见错误状态代码的默认纯文本处理程序,请在 Startup.Configure 方法中调用 UseStatusCodePages

app.UseStatusCodePages();

在请求处理中间件(例如,静态文件中间件和 MVC 中间件)前面调用 UseStatusCodePages

未使用 UseStatusCodePages 时,导航到没有终结点的 URL 会返回一条与浏览器相关的错误消息,指示找不到终结点。 例如,导航到 Home/Privacy2。 调用 UseStatusCodePages 时,浏览器返回:

Status Code: 404; Not Found

包含格式字符串的 UseStatusCodePages

若要自定义响应内容类型和文本,请利用需要使用内容类型和格式字符串的 UseStatusCodePages 重载:

app.UseStatusCodePages(
    "text/plain", "Status code page, status code: {0}");            

包含 lambda 的 UseStatusCodePages

若要指定自定义错误处理和响应写入代码,请利用需要使用 lambda 表达式的 UseStatusCodePages 重载:


app.UseStatusCodePages(async context =>
{
    context.HttpContext.Response.ContentType = "text/plain";

    await context.HttpContext.Response.WriteAsync(
        "Status code page, status code: " + 
        context.HttpContext.Response.StatusCode);
});

UseStatusCodePagesWithRedirects

UseStatusCodePagesWithRedirects 扩展方法:

  • 向客户端发送“302 - 已找到”状态代码。
  • 将客户端重定向到 URL 模板中的位置。
app.UseStatusCodePagesWithRedirects("/StatusCode?code={0}");

URL 模板可能会包括状态代码的 {0} 占位符,如上面的示例所示。 如果 URL 模板以波形符 ~(代字号)开头,则 ~ 会替换为应用的 PathBase。 如果在应用中指向终结点,请为终结点创建 MVC 视图或 Razor 页面。 有关 Razor Pages 示例,请参阅示例应用中的 Pages/StatusCode.cshtml。

使用此方法通常是当应用:

  • 应将客户端重定向到不同的终结点(通常在不同的应用处理错误的情况下)。 对于 Web 应用,客户端的浏览器地址栏反映重定向终结点。
  • 不应保留原始状态代码并通过初始重定向响应返回该代码。

UseStatusCodePagesWithReExecute

UseStatusCodePagesWithReExecute 扩展方法:

  • 向客户端返回原始状态代码。
  • 通过使用备用路径重新执行请求管道,从而生成响应正文。
app.UseStatusCodePagesWithReExecute("/StatusCode","?code={0}");

如果在应用中指向终结点,请为终结点创建 MVC 视图或 Razor 页面。 确保将 UseStatusCodePagesWithReExecute 放置在 UseRouting 之前,以便可以将请求重新路由到状态页。 有关 Razor Pages 示例,请参阅示例应用中的 Pages/StatusCode.cshtml。

使用此方法通常是当应用应:

  • 处理请求,但不重定向到不同终结点。 对于 Web 应用,客户端的浏览器地址栏反映最初请求的终结点。
  • 保留原始状态代码并通过响应返回该代码。

URL 模板和查询字符串模板可能包括状态代码的占位符 ({0})。 URL 模板必须以斜杠 (/) 开头。 若要在路径中使用占位符,请确认终结点(页或控制器)能否处理路径段。 例如,错误的 Razor 页面应通过 @page 指令接受可选路径段值:

@page "{code?}"

错误处理终结点可以获取生成错误的原始 URL,如下面的示例所示:

var statusCodeReExecuteFeature = HttpContext.Features.Get<IStatusCodeReExecuteFeature>();
if (statusCodeReExecuteFeature != null)
{
    OriginalURL =
        statusCodeReExecuteFeature.OriginalPathBase
        + statusCodeReExecuteFeature.OriginalPath
        + statusCodeReExecuteFeature.OriginalQueryString;
}

不要使用 HTTP 方法属性(如 HttpGet)标记错误处理程序操作方法。 显式谓词可阻止某些请求访问方法。 如果未经身份验证的用户应看到错误视图,则允许匿名访问该方法。

禁用状态代码页

若要禁用 MVC 控制器或操作方法的状态代码页,请使用 [SkipStatusCodePages] 特性。

若要禁用 Razor Pages 处理程序方法或 MVC 控制器中的特定请求的状态代码页,请使用 IStatusCodePagesFeature

var statusCodePagesFeature = HttpContext.Features.Get<IStatusCodePagesFeature>();

if (statusCodePagesFeature != null)
{
    statusCodePagesFeature.Enabled = false;
}

异常处理代码

异常处理页中的代码可能会引发异常。 建议在生产错误页面中包含纯静态内容。

响应头

在响应头发送后:

  • 应用无法更改响应的状态代码。
  • 任何异常页或处理程序都无法运行。 必须完成响应或中止连接。

服务器异常处理

除了应用中的异常处理逻辑外,HTTP 服务器实现还能处理一些异常。 如果服务器在发送响应标头之前捕获到异常,服务器将发送不包含响应正文的“500 - 内部服务器错误”响应。 如果服务器在发送响应标头后捕获到异常,服务器会关闭连接。 应用程序无法处理的请求将由服务器进行处理。 当服务器处理请求时,发生的任何异常都将由服务器的异常处理进行处理。 应用的自定义错误页面、异常处理中间件和筛选器都不会影响此行为。

启动异常处理

应用程序启动期间发生的异常仅可在承载层进行处理。 可以将主机配置为,捕获启动错误捕获详细错误

仅当错误在主机地址/端口绑定后出现时,托管层才能显示捕获的启动错误的错误页。 如果绑定失败:

  • 托管层将记录关键异常。
  • dotnet 进程崩溃。
  • 不会在 HTTP 服务器为 Kestrel 时显示任何错误页。

IIS(或 Azure 应用服务)或 IIS Express 上运行应用时,如果无法启动进程,ASP.NET Core 模块将返回“502.5 - 进程失败”。 有关详细信息,请参阅 对 Azure 应用服务和 IIS 上的 ASP.NET Core 进行故障排除

数据库错误页

数据库错误页中间件捕获与数据库相关的异常,可使用实体框架迁移来解析这些异常。 当这些异常出现时,便会生成 HTML 响应,其中包含用于解决问题的可能操作的详细信息。 应仅在开发环境中启用此页。 通过向 Startup.Configure 添加代码来启用此页:

if (env.IsDevelopment())
{
    app.UseDatabaseErrorPage();
}

UseDatabaseErrorPage 需要 Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore NuGet 包。

异常筛选器

在 MVC 应用中,可以全局配置异常筛选器,也可以为每个控制器或每个操作单独配置。 在 Razor Pages 应用中,可以全局配置异常筛选器,也可以为每个页面模型单独配置。 这些筛选器处理在执行控制器操作或其他筛选器时出现的任何未处理的异常。 有关详细信息,请参阅 ASP.NET Core 中的筛选器

提示

异常筛选器适合捕获 MVC 操作内发生的异常,但它们不如异常处理中间件灵活。 建议使用中间件。 仅在需要根据选定 MVC 操作以不同方式执行错误处理时,才使用筛选器。

模型状态错误

若要了解如何处理模型状态错误,请参阅模型绑定模型验证

其他资源