显示自定义错误页 (C#)

作者 :Scott Mitchell

ASP.NET Web 应用程序中发生运行时错误时,用户会看到什么? 答案取决于网站的 <customErrors> 配置方式。 默认情况下,用户将看到一个难看的黄色屏幕,声明发生了运行时错误。 本教程介绍如何自定义这些设置,以显示符合网站外观的美观自定义错误页面。

简介

在完美的世界中,不会有运行时错误。 程序员会编写带有 bug 和可靠用户输入验证的代码,而数据库服务器和电子邮件服务器等外部资源永远不会脱机。 当然,在现实中,错误是不可避免的。 .NET Framework中的类通过引发异常来发出错误信号。 例如,调用 SqlConnection 对象的 Open 方法会建立与连接字符串指定的数据库的连接。 但是,如果数据库关闭或连接字符串中的凭据无效,则 Open 方法将 SqlException引发 。 可以使用 块来处理 try/catch/finally 异常。 如果块中的 try 代码引发异常,则控制权将转移到相应的 catch 块,开发人员可在其中尝试从错误中恢复。 如果没有匹配的 catch 块,或者引发异常的代码不在 try 块中,则异常将向上扩展调用堆栈以搜索 try/catch/finally 块。

如果异常一直冒泡到 ASP.NET 运行时而不进行处理,HttpApplication则会引发类的 Error 事件,并显示配置的错误页。 默认情况下,ASP.NET 显示一个错误页,该页面被亲切地称为“ 死亡黄屏 ” (YSOD) 。 YSOD 有两个版本:一个版本显示异常详细信息、堆栈跟踪和其他有助于开发人员调试应用程序的信息 (请参阅 图 1) ;另一个只是指出存在运行时错误 (见 图 2) 。

异常详细信息 YSOD 对于调试应用程序的开发人员非常有用,但向最终用户显示 YSOD 是俗气和不专业的。 相反,最终用户应转到一个错误页面,该页面使用更用户友好的散文来描述情况,以保持网站的外观和感觉。 好消息是,创建这样的自定义错误页面非常简单。 本教程从 ASP 开始。NET 的不同错误页。 然后演示如何配置 Web 应用程序,以在遇到错误时向用户显示自定义错误页。

检查三种类型的错误页

当 ASP.NET 应用程序中出现未经处理的异常时,将显示以下三种类型的错误页之一:

  • “异常详细信息黄色死机屏幕”错误页,
  • “运行时错误死机黄色屏幕”错误页,或
  • 自定义错误页

开发人员最熟悉的错误页是异常详细信息 YSOD。 默认情况下,此页面显示给正在本地访问的用户,因此是在开发环境中测试站点时出错时看到的页面。 顾名思义,异常详细信息 YSOD 提供有关异常的详细信息 - 类型、消息和堆栈跟踪。 此外,如果异常是由 ASP.NET 页的代码隐藏类中的代码引发的,并且如果应用程序配置为调试,则异常详细信息 YSOD 还将显示此代码行 (以及上面和下方的几行代码) 。

图 1 显示了“异常详细信息 YSOD”页。 请注意浏览器地址窗口中的 URL: http://localhost:62275/Genre.aspx?ID=foo。 回想一下,该 Genre.aspx 页面列出了特定流派的书评。 它要求 GenreId 值 (uniqueidentifier) 通过查询字符串传递;例如,查看虚构评论的相应 URL 为 Genre.aspx?ID=7683ab5d-4589-4f03-a139-1c26044d0146。 如果通过查询字符串 ((如“foo”)传入非uniqueidentifier 值,) 将引发异常。

注意

若要在可供下载的演示 Web 应用程序中重现此错误,可以直接访问 Genre.aspx?ID=foo ,或单击 中的 Default.aspx“生成运行时错误”链接。

请注意 图 1 中提供的异常信息。 页面顶部显示异常消息“从字符串转换为 uniqueidentifier 时转换失败”。 还会列出异常 System.Data.SqlClient.SqlException的类型。 还有堆栈跟踪。

显示异常详细信息 YSOD 的屏幕截图,其中包含有关异常的信息。

图 1:异常详细信息 YSOD 包含有关异常的信息
(单击以查看全尺寸图像)

另一种类型的 YSOD 是运行时错误 YSOD, 如图 2 所示。 运行时错误 YSOD 通知访问者已发生运行时错误,但它不包括有关引发的异常的任何信息。 (它确实提供了有关如何通过修改 Web.config 文件来查看错误详细信息的说明,这是使此类 YSOD 看起来不专业的一部分。)

默认情况下,运行时错误 YSOD 显示给通过 http://www.yoursite.com) 远程 (访问的用户,如图 2 中浏览器地址栏中的 URL 所示: http://httpruntime.web703.discountasp.net/Genre.aspx?ID=foo。 存在两个不同的 YSOD 屏幕,因为开发人员有兴趣了解错误详细信息,但此类信息不应显示在实时网站上,因为它可能会向访问您的网站的任何人透露潜在的安全漏洞或其他敏感信息。

注意

如果你正在关注并使用 DiscountASP.NET 作为 Web 主机,你可能会注意到,访问实时站点时不显示运行时错误 YSOD。 这是因为 DiscountASP.NET 的服务器已配置为默认显示异常详细信息 YSOD。 好消息是,可以通过向文件添加 <customErrors> 节来 Web.config 替代此默认行为。 “配置显示哪个错误页”部分详细介绍了该 <customErrors> 部分。

显示运行时错误 YSOD 不包含任何错误详细信息的屏幕截图。

图 2:运行时错误 YSOD 不包含任何错误详细信息
(单击以查看全尺寸图像)

第三种类型的错误页是自定义错误页,它是你创建的网页。 自定义错误页的好处是可以完全控制向用户显示的信息以及页面的外观;自定义错误页可以使用与其他页面相同的母版页和样式。 “使用自定义错误页”部分逐步讲解如何创建自定义错误页并将其配置为在发生未经处理的异常时显示。 图 3 提供了此自定义错误页的偷偷峰值。 如你所看到的,错误页面的外观和感觉比图 1 和图 2 中显示的任何一个死亡黄屏更专业。

显示自定义错误页的屏幕截图,该页面演示了更定制的外观。

图 3:自定义错误页提供更定制的外观
(单击以查看全尺寸图像)

花点时间检查 图 3 中浏览器的地址栏。 请注意,“地址”栏显示) (/ErrorPages/Oops.aspx 自定义错误页的 URL。 在图 1 和图 2 中,死亡的黄色屏幕显示在错误源自 (Genre.aspx) 的同一页中。 自定义错误页通过 querystring 参数传递发生错误的页面的 aspxerrorpath URL。

配置显示哪个错误页

显示三个可能的错误页中的哪一个基于两个变量:

  • 部分中的配置信息 <customErrors> ,以及
  • 用户在本地还是远程访问站点。

<customErrors>中的 Web.config 节有两个属性,这些属性会影响显示的错误页: defaultRedirectmodedefaultRedirect 属性是可选项。 如果提供,则指定自定义错误页的 URL,并指示应显示自定义错误页,而不是运行时错误 YSOD。 属性 mode 是必需的,接受以下三个值之一: OnOffRemoteOnly。 这些值具有以下行为:

  • On - 指示向所有访问者显示自定义错误页或运行时错误 YSOD,无论他们是本地还是远程。
  • Off - 指定向所有访问者显示异常详细信息 YSOD,无论这些访问者是本地访问者还是远程访问者。
  • RemoteOnly - 指示向远程访问者显示自定义错误页或运行时错误 YSOD,而向本地访问者显示异常详细信息 YSOD。

除非另有指定,否则 ASP.NET 就像将 mode 属性设置为 RemoteOnly 但未指定值一 defaultRedirect 样。 换句话说,默认行为是向本地访问者显示异常详细信息 YSOD,同时向远程访问者显示运行时错误 YSOD。 可以通过向 Web 应用程序的 添加节 <customErrors> 来替代此默认行为 Web.config file.

使用自定义错误页

每个 Web 应用程序都应有一个自定义错误页。 它为运行时错误 YSOD 提供了更专业的替代方法,创建起来非常简单,将应用程序配置为使用自定义错误页只需几分钟时间。 第一步是创建自定义错误页。 我已向书评应用程序添加了一个名为 ErrorPages 的新文件夹,并向其添加了名为 Oops.aspx的新 ASP.NET 页。 让页面使用与网站上的其余页面相同的母版页,以便它自动继承相同的外观。

突出显示新的 ErrorPages 文件夹和关联的 Oops 点的 p x 文件的屏幕截图。

图 4:创建自定义错误页

接下来,花几分钟时间创建错误页的内容。 我创建了一个相当简单的自定义错误页面,其中包含一条消息,指示发生了意外错误,并提供了一个返回到网站主页的链接。

显示自定义错误页和关联消息的屏幕截图。

图 5:设计自定义错误页
(单击以查看全尺寸图像)

完成错误页后,将 Web 应用程序配置为使用自定义错误页来代替运行时错误 YSOD。 这是通过在 节的 属性中 <customErrors> 指定错误页的 URL 来实现的 defaultRedirect 。 将以下标记添加到应用程序的 Web.config 文件中:

<configuration>
    ...

    <system.web>
        <customErrors mode="RemoteOnly"
                      defaultRedirect="~/ErrorPages/Oops.aspx" />

        ...
    </system.web>
</configuration>

上述标记将应用程序配置为向本地访问的用户显示异常详细信息 YSOD,同时为远程访问的用户使用自定义错误页 Oops.aspx。 若要查看此操作,请将网站部署到生产环境,然后使用无效的查询字符串值访问实时站点上的 Genre.aspx 页面。 应看到自定义错误页, (参考 图 3) 。

若要验证自定义错误页是否仅向远程用户显示,请从开发环境中访问 Genre.aspx 具有无效查询字符串的页面。 仍应看到异常详细信息 YSOD (请参阅 图 1) 。 设置 RemoteOnly 可确保在生产环境中访问站点的用户看到自定义错误页,而在本地工作的开发人员可继续查看异常的详细信息。

通知开发人员和日志记录错误详细信息

开发环境中发生的错误是由坐在计算机中的开发人员引起的。 她在异常详细信息 YSOD 中显示异常信息,并且她知道发生错误时她正在执行哪些步骤。 但是,当生产环境中发生错误时,除非访问站点的最终用户花费时间报告错误,否则开发人员不知道发生了错误。 即使用户在不知道异常类型、消息和堆栈跟踪的情况下不尽如人意地向开发团队发出错误警报,也很难诊断错误的原因,更别说修复了。

出于这些原因,将生产环境中的任何错误记录到某些持久性存储 ((例如数据库) ),并且开发人员必须收到此错误的警报。 自定义错误页似乎是执行此日志记录和通知的好地方。 遗憾的是,自定义错误页无权访问错误详细信息,因此不能用于记录此信息。 好消息是,有多种方法可以截获错误详细信息并记录它们,接下来的三个教程将更详细地探讨本主题。

对不同的 HTTP 错误状态使用不同的自定义错误页

当异常由 ASP.NET 页引发且未处理时,该异常会持续到 ASP.NET 运行时,该运行时会显示配置的错误页。 如果请求进入 ASP.NET 引擎,但由于某种原因而无法处理 (可能找不到请求的文件或已禁用该文件的读取权限),则 ASP.NET 引擎会 HttpException引发 。 此异常与从 ASP.NET 页引发的异常一样,会浮升到运行时,从而导致显示相应的错误页。

对于生产中的 Web 应用程序,这意味着如果用户请求未找到的页面,则他们将看到自定义错误页。 图 6 显示了这样一个示例。 由于请求针对不存在的页 (NoSuchPage.aspx) , HttpException 因此将引发 并显示自定义错误页, (在 querystring 参数) 记下对 NoSuchPage.aspxaspxerrorpath 的引用。

显示 A S P dot NET 运行时如何显示配置的错误页的屏幕截图。

图 6:ASP.NET 运行时在响应无效请求时显示配置的错误页 (单击以查看全尺寸图像)

默认情况下,所有类型的错误都会导致显示相同的自定义错误页。 但是,可以使用 节中的<customErrors>子元素为特定 HTTP 状态代码<error>指定不同的自定义错误页。 例如,若要在出现 HTTP 状态代码为 404 的“找不到页面”错误时显示其他错误页,请更新 <customErrors> 节以包含以下标记:

<customErrors mode="RemoteOnly" defaultRedirect="~/ErrorPages/Oops.aspx">
    <error statusCode="404" redirect="~/ErrorPages/404.aspx" />
</customErrors>

进行此更改后,每当远程访问的用户请求不存在的 ASP.NET 资源时,他们将被重定向到 404.aspx 自定义错误页而不是 Oops.aspx。 如图 7 所示,页面 404.aspx 可以包含比常规自定义错误页更具体的消息。

注意

请查看 404 错误页,再查看一次 ,获取有关创建有效 404 错误页的指导。

显示自定义 4 O 4 错误页的屏幕截图。

图 7:自定义 404 错误页显示的目标性比 Oops.aspx
(单击以查看全尺寸图像)

因为你知道 404.aspx ,只有在用户请求找不到的页面时才会访问该页面,因此可以增强此自定义错误页,以包含帮助用户解决此特定错误类型的功能。 例如,可以生成将已知错误 URL 映射到良好 URL 的数据库表,然后让 404.aspx 自定义错误页针对该表运行查询,并建议用户可能尝试访问的页面。

注意

仅当向 ASP.NET 引擎处理的资源发出请求时,才会显示自定义错误页。 正如我们在 IIS 与 ASP.NET Development Server 之间的核心差异 教程中所述,Web 服务器本身可以处理某些请求。 默认情况下,IIS Web 服务器在不调用 ASP.NET 引擎的情况下处理静态内容(如图像和 HTML 文件)的请求。 因此,如果用户请求不存在的图像文件,他们将返回 IIS 的默认 404 错误消息,而不是 ASP。NET 的已配置错误页。

总结

当 ASP.NET 应用程序中发生未经处理的异常时,用户会显示以下三个错误页之一:异常详细信息死亡黄色屏幕;运行时错误黄色死机屏幕;或自定义错误页。 显示哪个错误页取决于应用程序的 <customErrors> 配置以及用户是在本地访问还是远程访问。 默认行为是向本地访问者显示异常详细信息 YSOD,向远程访问者显示运行时错误 YSOD。

虽然运行时错误 YSOD 对访问站点的用户隐藏潜在的敏感信息,但它会破坏站点的外观,使应用程序看起来有 bug。 更好的方法是使用自定义错误页,这需要创建和设计自定义错误页,并在节的 defaultRedirect 属性中<customErrors>指定其 URL。 甚至可以针对不同的 HTTP 错误状态创建多个自定义错误页。

自定义错误页是生产环境中网站综合错误处理策略的第一步。 向开发人员发出错误警报并记录其详细信息也是重要的步骤。 接下来的三个教程将探讨错误通知和日志记录的技术。

编程愉快!

深入阅读

有关本教程中讨论的主题的详细信息,请参阅以下资源: