• 推荐
  • 评论
  • 收藏

ASP.NET 自定义错误处理 (Web.Config - customErrors)

2021-10-13    5881次浏览
我们将使用ASP.NET开发的Web应用程序发布后,如果代码发生了错误,默认情况下会直接将错误的详细信息展示在网页页面中,这对于生产环境来说是非常不友好的,为了安全和用户体验等考虑,我们需要配置自定义错误处理程序来提高我们应用的安全性和用户体验。
通过查询官方文档(https://docs.microsoft.com/zh-cn/previous-versions/dotnet/netframework-2.0/h0hfz6fc(v=vs.80)),我们可以了解到:在Web应用的配置文件:Web.Config中使用customErrors配置项就可以自定义错误处理页面了!如下为customErrors配置元素的使用说明:

customErrors 元素

属性 说明
defaultRedirect 可选的属性。指定出错时将浏览器定向到的默认 URL。如果未指定该属性,则显示一般性错误。
URL 可以是绝对的(如 www.contoso.com/ErrorPage.htm)或相对的。相对 URL(如 /ErrorPage.htm)是相对于为该属性指定 URL 的 Web.config 文件,而不是相对于发生错误的网页。以字符 (~) 开头的 URL(如 ~/ErrorPage.htm)表示指定的 URL 是相对于应用程序的根路径。
mode 必选的属性。指定是启用或禁用自定义错误,还是仅向远程客户端显示自定义错误。
可选值以及说明:
On        指定启用自定义错误。如果未指定 defaultRedirect,用户将看到一般性错误。
Off        指定禁用自定义错误。这允许显示标准的详细错误。
RemoteOnly  指定仅向远程客户端显示自定义错误并且向本地主机显示 ASP.NET 错误。这是默认值。
默认值为 RemoteOnly。

customErrors 子元素

元素 说明
error 可选的元素。指定给定 HTTP 状态代码的自定义错误页。
错误标记可以出现多次。子标记的每一次出现均定义一个自定义错误条件。

配置示例

<configuration>
  <system.web>
    <customErrors defaultRedirect="defaultError.htm"  //发生错误时,重定向到defaultError.htm
                  mode="RemoteOnly">           //仅仅对本地用户显示详细错误信息
      <error statusCode="500"               //针对500错误,跳转到500Error.htm
             redirect="500Error.htm"/>
    </customErrors>
  </system.web>
</configuration>

在程序中动态读取和修改 customErrors的配置数据

该配置参数对应的类为:System.Web.Configuration.CustomErrorsSection,下面以程序示例如何在程序中读取和修改 Web.config中的 customErrors配置:
public void Page_Load(object sender, EventArgs e)
{
    //<customErrors defaultRedirect="defaultError.htm" mode="Off">
    //  <error statusCode="500" redirect="500.htm"/>
    //</customErrors>

    //CustomErrorsSection customErrorsSection = ConfigurationManager.GetSection("system.web/customErrors") as CustomErrorsSection;    //这样获取也可以,但是要注意里面的路径的写法
    CustomErrorsSection CES = (CustomErrorsSection)WebConfigurationManager.OpenWebConfiguration("/").GetSection("system.web/customErrors");
    Response.Write(CES.DefaultRedirect);    //输出 defaultError.htm
    CustomErrorsMode mode = CES.Mode;
    Response.Write(mode);       //输出 Off

    CustomError CE = CES.Errors[0]; //获取其下的第一个子<error>节点
    Response.Write(CE.StatusCode);  //输出 500
    Response.Write(CE.Redirect);    //输出 500.htm

    ElementInformation EleInfo = CES.ElementInformation;    //元素信息
    Response.Write(EleInfo.LineNumber);     //输出 14 恰好是customErrors所在Web.Config的行号

    System.Configuration.Configuration c = CES.CurrentConfiguration;   //当前Configuration对象的引用
    Response.Write(CES.IsReadOnly());     //输出 False 指示该节点是否为只读
    Response.Write(CES.LockItem);         //输出 False 是否已锁定该元素
    Response.Write(CES.RedirectMode);     //输出 ResponseRedirect 一个枚举  将用户重定向到自定义错误页面时,是否应该更改请求的URL

    SectionInformation SI = CES.SectionInformation;
    Response.Write(SI.Name);     //输出 customErrors

}

在错误页面中获取错误信息

通过查找发现一旦使用了配置customErrors之后,就不会在代码中获取到错误信息了;下面是另一种对错误处理的解决方案,大家可以参考使用。(在 Global.asax页面中的Application_Error事件中添加错误处理逻辑:发生错误后进行页面跳转,并将错误信息携带在URL中,在错误页中,根据URL中的参数,就可以获取错误信息并显示出来)。
void Application_Error(object sender, EventArgs e)
{
  //在出现未处理的错误时运行的代码
  
  HttpContext ctx = HttpContext.Current;
  Exception exception = ctx.Server.GetLastError();
  
  //错误跳转URL
  string directUrl = "DefaultError.html?error=";
  
  if (exception != null)
  {
      string errorInfo = "URL:" + ctx.Request.RawUrl.ToString() + "Source:" + exception.Source
      + "Message:<strong>" + exception.Message + "</strong>";
      errorInfo = "错误信息为:<strong>" + exception.InnerException.Message + "</strong>";
      
      string url=ctx.Request.Url.ToString();
      directUrl = url.Substring(0, url.ToString().IndexOf("/Web/") + 5) + directUrl + errorInfo;
      directUrl += "&referurl=" + ctx.Request.Url.ToString();
      ctx.Items.Add("LastError", errorInfo);
      ctx.Server.ClearError();
      
      //这里可以根据异常类型进行处理
      //if (exception is HttpException)
      //{
      //    HttpException ex = exception as HttpException;
      //    int httpCode = ex.GetHttpCode();
      //    errorInfo = "Code:<strong>" + httpCode.ToString() + "</strong>" + errorInfo;
      //if (httpCode == 404)
      //{
      //    directUrl = "~/DefaultError.html?error=" + errorInfo;
      //}
      //if (httpCode == 403 || httpCode == 402 || httpCode == 401)
      //{
      //    directUrl = "~/DefaultError.html?error=" + errorInfo;
      //}
      //}
      
  }
  try
  {
      //ctx.Server.Transfer(directUrl);
      ctx.Response.Redirect(directUrl);
  }
  catch
  {
      //可记录错误日志 
  }
  
}