zoukankan      html  css  js  c++  java
  • Web API系列(三)统一异常处理

      前面讲了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调用路径,在浏览器中获得下面错误结果。

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

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

     /// <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里面异常的处理机制,可能还不够深入,但对于一般项目的异常处理基本够用。其他朋友,如果还有什么更好的方案,还望不吝赐教,感谢感谢!

      其次,我们目前使用的异常处理,参考于http://www.cnblogs.com/wuhuacong/p/4843422.html。

  • 相关阅读:
    Appium脚本(2):元素检测
    查看appPackage和appActivity的多种方法
    让织梦内容页arclist标签的当前文章标题加亮显示
    dedecms wap 上一篇 下一篇 链接出错
    织梦开启二级域名(多站点)内容页图片无法显示的解决方法
    多级分类标签{dede:channelartlist}实现当前栏目颜色高亮显示
    织梦channelartlist标签当前栏目高亮
    dedecms模板中 if else怎么写
    dedecms调用子栏目及文章列表
    Dedecms判断当前栏目下是否有子栏目
  • 原文地址:https://www.cnblogs.com/zhangweizhong/p/6225196.html
Copyright © 2011-2022 走看看