前面讲了webapi的安全验证和参数安全,不清楚的朋友,可以看看前面的文章,《Web API系列(二)接口安全和参数校验》,本文主要介绍Web API异常结果的处理。作为内部或者是对外提供的统一webapi 接口,统一的异常处理,把正确的信息返回给调用者很重要。这样可以让接口开发人员,了解具体的原因所在,这样可以得到有效的错误处理。

  需要注意的是,webapi异常的状态码,尽量不要和业务状态码混淆。可以分为两个不同的字段,或者是状态码的规则不同。相关返回数据的格式,可以参考,前面的文章。

1、常规程序异常处理

  常规的程序异常,指的是webapi 接口程序在执行的时候出现的各种异常情况,可以使用异常筛选器捕获所有异常。

  1. API自定义错误过滤器属性:ApiExceptionAttribute

    /// <summary>
    /// API自定义错误过滤器属性
    /// </summary>
    public class ApiExceptionHandlingAttribute : ExceptionFilterAttribute
    {
        /// <summary>
        /// 统一对调用异常信息进行处理,返回自定义的异常信息
        /// </summary>
        /// <param name="context">HTTP上下文对象</param>
        public override void OnException(HttpActionExecutedContext context)
        {
            //自定义异常的处理
            if (context.Exception is NotImplementedException)
            {
                throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotImplemented) 
                {
                    //封装处理异常信息,返回指定JSON对象
                    Content = new StringContent(JsonHelper.ToJson(new ErrorModel((int)HttpStatusCode.NotImplemented, 0, ex.Message)), Encoding.UTF8, "application/json"),
                    ReasonPhrase = "NotImplementedException"
                });
            }
            else if (context.Exception is TimeoutException)
            {
                throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.RequestTimeout)
                {
                    //封装处理异常信息,返回指定JSON对象
                    Content = new StringContent(JsonHelper.ToJson(new ErrorModel((int)HttpStatusCode.RequestTimeout, 0, ex.Message)), Encoding.UTF8, "application/json"),
                    ReasonPhrase = "TimeoutException"
                });
            }
            //.....这里可以根据项目需要返回到客户端特定的状态码。如果找不到相应的异常,统一返回服务端错误500
            else
            {
                throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.InternalServerError)
                {
                    //封装处理异常信息,返回指定JSON对象
                    Content = new StringContent(JsonHelper.ToJson(new ErrorModel((int)HttpStatusCode.InternalServerError, 0, ex.Message)), Encoding.UTF8, "application/json"),
                    ReasonPhrase = "InternalServerErrorException"
                });
            }

            //base.OnException(context);

            //记录关键的异常信息
            //Debug.WriteLine(context.Exception);
        }
    }

 

  2. 定义好了错误过滤器,根据实际情况,在不同级别使用统一的异常处理机制。比如,接口action级别,控制器Controller级别或者是全局。

  我们目前的使用的是全局进行异常过滤。在ApiBase 增加异常过滤。

    [ApiAuth]
    [ApiExceptionHandling]
    public class ApiBase : ApiController

2、地址接口异常处理

  对于常规的异常,我们通过上面的处理方式,就可以很好进行拦截并处理了,如果接口异常是全局性的,如访问地不正确,或者调用的接口就不是有效的地址,这样的话,返回的信息就不会被上面的拦截器进行处理了。

如我们给一个无效的API调用路径,在浏览器中获得下面错误结果。

Web API系列(三)统一异常处理_Web Api

  由于上面结果就无法被我们的常规异常拦截器所捕获,因此不会输出经过封装好的异常信息。

  所以如果需要拦截,我们需要增加自己的消息代理处理,用来捕获这些特殊的异常信息。

 /// <summary>
    /// API自定义错误消息处理委托类。
    /// 用于处理访问不到对应API地址的情况,对错误进行自定义操作。
    /// </summary>
    public class CustomErrorMessageDelegatingHandler : DelegatingHandler
    {
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            return base.SendAsync(request, cancellationToken).ContinueWith<HttpResponseMessage>((responseToCompleteTask) =>
            {
                HttpResponseMessage response = responseToCompleteTask.Result;
                HttpError error = null;
                if (response.TryGetContentValue<HttpError>(out error))
                {
                    //添加自定义错误处理
                    //error.Message = "Your Customized Error Message";
                }

                if (error != null)
                {
                    //获取抛出自定义异常,有拦截器统一解析
                    throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound)
                    {
                        //封装处理异常信息,返回指定JSON对象
                        Content = new StringContent(JsonHelper.ToJson(new ErrorModel(404, 0, error.Message)), Encoding.UTF8, "application/json"),
                        ReasonPhrase = "Exception"
                    });
                }
                else
                {
                    return response;
                }
            });
        }
    }

  同时,在WebApiConfig中,注册上相关处理

 public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
    
            ..............

            config.MessageHandlers.Add(new CustomErrorMessageDelegatingHandler());

  有了以上这两种异常处理,我们就可以统一我们的调用规则,并进行异常记录和显示了,非常方便。

3、总结

  首先,以上这两种异常处理,我们就可以统一我们的调用规则,但是对于WebApi里面异常的处理机制,可能还不够深入,但对于一般项目的异常处理基本够用。其他朋友,如果还有什么更好的方案,还望不吝赐教,感谢感谢!

 

 


作者:章为忠


关注我的微信公众号,获取相关的 源代码及视频资料
Web API系列(三)统一异常处理_统一异常处理_02