• ASP.NET MVC 异常Exception拦截


    一、前言

    由于客户端的环境不一致,有可能会造成我们预计不到的异常错误,所以在项目中,友好的异常信息提示,是非常重要的。asp.net mvc中实现异常属性拦截也非常简单,只需要继承另一个类(System.Web.Mvc.FilterAttribute)和一个接口(System.Web.Mvc.IExceptionFilter),实现接口里面OnException方法,或者直接继承Mvc 提供的类System.Web.Mvc.HandleErrorAttribute

    二、实现关键逻辑

    继承System.Web.Mvc.HandleErrorAttribute,重写了OnException方法,主要实现逻辑代码如下:

    1. public class HandlerErrorAttribute : HandleErrorAttribute
    2. {
    3.     /// <summary>
    4.     /// 控制器方法中出现异常,会调用该方法捕获异常
    5.     /// </summary>
    6.     /// <param name="context">提供使用</param>
    7.     public override void OnException(ExceptionContext context)
    8.     {
    9.         WriteLog(context);
    10.         base.OnException(context);
    11.         context.ExceptionHandled = true;
    12.         if (context.Exception is UserFriendlyException)
    13.         {
    14.             context.HttpContext.Response.StatusCode = (int)HttpStatusCode.OK;
    15.             context.Result = new ContentResult { Content = new AjaxResult { type = ResultType.error, message = context.Exception.Message }.ToJson() };
    16.         }
    17.         else if (context.Exception is NoAuthorizeException)
    18.         {
    19.             context.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
    20.             if (!context.HttpContext.Request.IsAjaxRequest())
    21.             {
    22.                 context.HttpContext.Response.RedirectToRoute("Default", new { controller = "Error", action = "Error401", errorUrl = context.HttpContext.Request.RawUrl });
    23.             }
    24.             else
    25.             {
    26.                 context.Result = new ContentResult { Content = context.HttpContext.Request.RawUrl };
    27.             }
    28.         }
    29.         else
    30.         {
    31.              context.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
    32.              ExceptionMessage error = new ExceptionMessage(context.Exception);
    33.              var s = error.ToJson();
    34.              if (!context.HttpContext.Request.IsAjaxRequest())
    35.              {
    36.                  context.HttpContext.Response.RedirectToRoute("Default", new { controller = "Error", action = "Error500", data = WebHelper.UrlEncode(s) });
    37.              }
    38.              else
    39.              {
    40.                  context.Result = new ContentResult { Content = WebHelper.UrlEncode(s) };
    41.              }
    42.         }
    43.     }
    44.  
    45.     /// <summary>
    46.     /// 写入日志(log4net)
    47.     /// </summary>
    48.     /// <param name="context">提供使用</param>
    49.     private void WriteLog(ExceptionContext context)
    50.     {
    51.         if (context == null)
    52.             return;
    53.         if (context.Exception is NoAuthorizeException || context.Exception is UserFriendlyException)
    54.         {
    55.             //友好错误提示,未授权错误提示,记录警告日志
    56.             LogHelper.Warn(context.Exception.Message);
    57.         }
    58.         else
    59.         {
    60.             //异常错误,
    61.             LogHelper.Error(context.Exception);
    62.  
    63.             ////TODO :写入错误日志到数据库
    64.         }
    65.     }
    66. }

    MVC 过滤器全局注册异常拦截:

    1. public class FilterConfig
    2.     {
    3.         public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    4.         {
    5.             filters.Add(new HandlerErrorAttribute());
    6.         }
    7.     }

    我们看到,context.Exception 分为3种:UserFriendlyException,NoAuthorizeException 或 Exception;UserFriendlyException 是指友好异常,前端友好提示错误信息。NoAuthorizeException 为401未授权异常,当页面未被授权访问时,返回该异常,并携带有未授权的路径地址。其他异常统一返回500错误,并携带异常信息。

    三、异常处理

    1.401 未授权错误

    异常定义代码:

    1. /// <summary>
    2. /// 没有被授权的异常
    3. /// </summary>
    4. public class NoAuthorizeException : Exception
    5. {
    6.     public NoAuthorizeException(string message)
    7.         : base(message)
    8.     {
    9.     }
    10. }

    抛出异常代码:

    1. throw new NoAuthorizeException("未授权");

    前端UI效果:

    2.404 未找到页面错误

    MVC的404异常处理,有几种方式,我们采用了在Global.asax全局请求函数中处理, 请查看以下代码

    1. protected void Application_EndRequest()
    2.      {
    3.          if (Context.Response.StatusCode == 404)
    4.          {
    5.              bool isAjax = new HttpRequestWrapper(Context.Request).IsAjaxRequest();
    6.              if (isAjax)
    7.              {
    8.                  Response.Clear();
    9.                  Response.Write(Context.Request.RawUrl);
    10.              }
    11.              else
    12.              {
    13.                  Response.RedirectToRoute("Default", new { controller = "Error", action = "Error404", errorUrl = Context.Request.RawUrl });
    14.              }
    15.          }
    16.      }

    前端UI效果:

    3.500服务器内部错误

    500异常错误抛出的异常信息对象定义:

    1. /// <summary>
    2. /// 异常错误信息
    3. /// </summary>
    4. [Serializable]
    5. public class ExceptionMessage
    6. {
    7.     public ExceptionMessage()
    8.     {
    9.     }
    10.  
    11.     /// <summary>
    12.     /// 构造函数
    13.     /// 默认显示异常页面
    14.     /// </summary>
    15.     /// <param name="ex">异常对象</param>
    16.     public ExceptionMessage(Exception ex)
    17.         :this(ex, true)
    18.     {
    19.  
    20.     }
    21.     /// <summary>
    22.     /// 构造函数
    23.     /// </summary>
    24.     /// <param name="ex">异常对象</param>
    25.     /// <param name="isShowException">是否显示异常页面</param>
    26.     public ExceptionMessage(Exception ex, bool isShowException)
    27.     {
    28.         MsgType = ex.GetType().Name;
    29.         Message = ex.InnerException != null ? ex.InnerException.Message : ex.Message;
    30.         StackTrace = ex.StackTrace.Length > 300 ? ex.StackTrace.Substring(0, 300) : ex.StackTrace;
    31.         Source = ex.Source;
    32.         Time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
    33.         Assembly = ex.TargetSite.Module.Assembly.FullName;
    34.         Method = ex.TargetSite.Name;
    35.  
    36.         ShowException = isShowException;
    37.         var request = HttpContext.Current.Request;
    38.         IP = Net.Ip;
    39.         UserAgent = request.UserAgent;
    40.         Path = request.Path;
    41.         HttpMethod = request.HttpMethod;
    42.     }
    43.     /// <summary>
    44.     /// 消息类型
    45.     /// </summary>
    46.     public string MsgType { get; set; }
    47.  
    48.     /// <summary>
    49.     /// 消息内容
    50.     /// </summary>
    51.     public string Message { get; set; }
    52.  
    53.     /// <summary>
    54.     /// 请求路径
    55.     /// </summary>
    56.     public string Path { get; set; }
    57.  
    58.     /// <summary>
    59.     /// 程序集名称
    60.     /// </summary>
    61.     public string Assembly { get; set; }
    62.  
    63.     /// <summary>
    64.     /// 异常参数
    65.     /// </summary>
    66.     public string ActionArguments { get; set; }
    67.  
    68.     /// <summary>
    69.     /// 请求类型
    70.     /// </summary>
    71.     public string HttpMethod { get; set; }
    72.  
    73.     /// <summary>
    74.     /// 异常堆栈
    75.     /// </summary>
    76.     public string StackTrace { get; set; }
    77.  
    78.     /// <summary>
    79.     /// 异常源
    80.     /// </summary>
    81.     public string Source { get; set; }
    82.  
    83.     /// <summary>
    84.     /// 服务器IP 端口
    85.     /// </summary>
    86.     public string IP { get; set; }
    87.  
    88.     /// <summary>
    89.     /// 客户端浏览器标识
    90.     /// </summary>
    91.     public string UserAgent { get; set; }
    92.  
    93.  
    94.     /// <summary>
    95.     /// 是否显示异常界面
    96.     /// </summary>
    97.     public bool ShowException { get; set; }
    98.  
    99.     /// <summary>
    100.     /// 异常发生时间
    101.     /// </summary>
    102.     public string Time { get; set; }
    103.  
    104.     /// <summary>
    105.     /// 异常发生方法
    106.     /// </summary>
    107.     public string Method { get; set; }
    108. }

    抛出异常代码:

    1. throw new Exception("出错了");

    前端UI效果:

    4. UserFriendlyException 友好异常

    异常定义代码:

    1. /// <summary>
    2. /// 用户友好异常
    3. /// </summary>
    4. public class UserFriendlyException : Exception
    5. {
    6.     public UserFriendlyException(string message)
    7.         : base(message)
    8.     {
    9.     }
    10. }

    在异常拦截关键代码中,我们发现友好异常(UserFriendlyException)其实是返回了一个结果对象AjaxResult,

    AjaxResult对象的定义:

    1. /// <summary>
    2.     /// 表示Ajax操作结果
    3.     /// </summary>
    4.     public class AjaxResult
    5.     {
    6.         /// <summary>
    7.         /// 获取 Ajax操作结果类型
    8.         /// </summary>
    9.         public ResultType type { get; set; }
    10.  
    11.         /// <summary>
    12.         /// 获取 Ajax操作结果编码
    13.         /// </summary>
    14.         public int errorcode { get; set; }
    15.  
    16.         /// <summary>
    17.         /// 获取 消息内容
    18.         /// </summary>
    19.         public string message { get; set; }
    20.  
    21.         /// <summary>
    22.         /// 获取 返回数据
    23.         /// </summary>
    24.         public object resultdata { get; set; }
    25.     }
    26.     /// <summary>
    27.     /// 表示 ajax 操作结果类型的枚举
    28.     /// </summary>
    29.     public enum ResultType
    30.     {
    31.         /// <summary>
    32.         /// 消息结果类型
    33.         /// </summary>
    34.         info = 0,
    35.  
    36.         /// <summary>
    37.         /// 成功结果类型
    38.         /// </summary>
    39.         success = 1,
    40.  
    41.         /// <summary>
    42.         /// 警告结果类型
    43.         /// </summary>
    44.         warning = 2,
    45.  
    46.         /// <summary>
    47.         /// 异常结果类型
    48.         /// </summary>
    49.         error = 3
    50.     }

    四、Ajax请求异常时处理

    在异常拦截的关键代码中,我们有看到,如果是ajax请求时,是执行不同的逻辑,这是因为ajax的请求,不能直接通过MVC的路由跳转,在请求时必须返回结果内容

    然后在前端ajax的方法中,统一处理返回的错误,以下是我们项目中用到的ajax封装,对异常错误,进行了统一处理。

    1. (function ($) {
    2.     "use strict";
    3.  
    4.     $.httpCode = {
    5.         success: "1",
    6.         fail: "3",
    7.     };
    8.     // http 通信异常的时候调用此方法
    9.     $.httpErrorLog = function (msg) {
    10.         console.log('=====>' + new Date().getTime() + '<=====');
    11.         console.log(msg);
    12.     };
    13.  
    14.     // ajax请求错误处理
    15.     $.httpError = function (xhr, textStatus, errorThrown) {
    16.  
    17.         if (xhr.status == 401) {
    18.             location.href = "/Error/Error401?errorUrl=" + xhr.responseText;
    19.         }
    20.  
    21.         if (xhr.status == 404) {
    22.             location.href = "/Error/Error404?errorUrl=" + xhr.responseText;
    23.         }
    24.  
    25.         if (xhr.status == 500) {
    26.             location.href = "/Error/Error500?data=" + xhr.responseText;
    27.         }
    28.     };
    29.  
    30.     /* get请求方法(异步):
    31.     * url地址, param参数, callback回调函数 beforeSend 请求之前回调函数, complete 请求完成之后回调函数
    32.     * 考虑到get请求一般将参数与url拼接一起传递,所以将param参数放置最后
    33.     * 返回AjaxResult结果对象
    34.     */
    35.     $.httpAsyncGet = function (url, callback, beforeSend, complete, param) {
    36.         $.ajax({
    37.             url: url,
    38.             data: param,
    39.             type: "GET",
    40.             dataType: "json",
    41.             async: true,
    42.             cache: false,
    43.             success: function (data) {
    44.                 if ($.isFunction(callback)) callback(data);
    45.             },
    46.             error: function (XMLHttpRequest, textStatus, errorThrown) {
    47.                 $.httpError(XMLHttpRequest, textStatus, errorThrown);
    48.             },
    49.             beforeSend: function () {
    50.                 if (!!beforeSend) beforeSend();
    51.             },
    52.             complete: function () {
    53.                 if (!!complete) complete();
    54.             }
    55.         });
    56.     };
    57.  
    58.     /* get请求方法(同步):
    59.     * url地址,param参数
    60.     * 返回实体数据对象
    61.     */
    62.     $.httpGet = function (url, param) {
    63.         var res = {};
    64.         $.ajax({
    65.             url: url,
    66.             data: param,
    67.             type: "GET",
    68.             dataType: "json",
    69.             async: false,
    70.             cache: false,
    71.             success: function (data) {
    72.                 res = data;
    73.             },
    74.             error: function (XMLHttpRequest, textStatus, errorThrown) {
    75.                 $.httpError(XMLHttpRequest, textStatus, errorThrown);
    76.             },
    77.         });
    78.         return res;
    79.     };
    80.  
    81.     /* post请求方法(异步):
    82.     * url地址, param参数, callback回调函数 beforeSend 请求之前回调函数, complete 请求完成之后回调函数
    83.     * 返回AjaxResult结果对象
    84.     */
    85.     $.httpAsyncPost = function (url, param, callback, beforeSend, complete) {
    86.         $.ajax({
    87.             url: url,
    88.             data: param,
    89.             type: "POST",
    90.             dataType: "json",
    91.             async: true,
    92.             cache: false,
    93.             success: function (data) {
    94.                 if ($.isFunction(callback)) callback(data);
    95.             },
    96.             error: function (XMLHttpRequest, textStatus, errorThrown) {
    97.                 $.httpError(XMLHttpRequest, textStatus, errorThrown);
    98.             },
    99.             beforeSend: function () {
    100.                 if (!!beforeSend) beforeSend();
    101.             },
    102.             complete: function () {
    103.                 if (!!complete) complete();
    104.             }
    105.         });
    106.     };
    107.  
    108.     /* post请求方法(同步):
    109.     * url地址,param参数, callback回调函数
    110.     * 返回实体数据对象
    111.     */
    112.     $.httpPost = function (url, param, callback) {
    113.         $.ajax({
    114.             url: url,
    115.             data: param,
    116.             type: "POST",
    117.             dataType: "json",
    118.             async: false,
    119.             cache: false,
    120.             success: function (data) {
    121.                 if ($.isFunction(callback)) callback(data);
    122.             },
    123.             error: function (XMLHttpRequest, textStatus, errorThrown) {
    124.                 $.httpError(XMLHttpRequest, textStatus, errorThrown);
    125.             },
    126.         });
    127.     },
    128.  
    129.     /* ajax异步封装:
    130.     * type 请求类型, url地址, param参数, callback回调函数
    131.     * 返回实体数据对象
    132.     */
    133.     $.httpAsync = function (type, url, param, callback) {
    134.         $.ajax({
    135.             url: url,
    136.             data: param,
    137.             type: type,
    138.             dataType: "json",
    139.             async: true,
    140.             cache: false,
    141.             success: function (data) {
    142.                 if ($.isFunction(callback)) callback(data);
    143.             },
    144.             error: function (XMLHttpRequest, textStatus, errorThrown) {
    145.                 $.httpError(XMLHttpRequest, textStatus, errorThrown);
    146.             },
    147.         });
    148.     };
    149. })(jQuery);

    五、总结

    至此,我们发现其实MVC的异常处理,真的很简单,只需要在过滤器中全局注册之后,然后重写OnException的方法,实现逻辑即可。关键是在于项目中Ajax请求,需要用统一的封装方法。

  • 相关阅读:
    Hdu 5595 GTW likes math
    HNOI2002 营业额统计(Splay Tree)
    hdu 5592 BestCoder Round #65(树状数组)
    hdu 5591 BestCoder Round #65(博弈)
    hdu5586 BestCoder Round #64 (div.2)
    NoSQL
    什么是关系型数据库
    关系型数据库与NOSQL
    关系型数据库
    centos6.x下安装eclipse
  • 原文地址:https://www.cnblogs.com/xyb0226/p/9250334.html
Copyright © 2020-2023  润新知