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。

  • 相关阅读:
    [译文] 实体与值对象到底是不是一回事?
    实现 WebApi 自托管服务宿主于 WinForms 及其交互
    [译文] C# 8 已成旧闻, 向前, 抵达 C# 9!
    [译文] 为什么你在 C# 里总是应该使用 "var" 关键字
    通过设置iis在局域网中访问网页
    windows 10 安装使用kafka
    ASP.NET Core 2.1 中的 HttpClientFactory (Part 4) 整合Polly实现瞬时故障处理
    ASP.NET Core 2.1 中的 HttpClientFactory (Part 3) 使用Handler实现传出请求中间件
    ASP.NET Core 2.1 中的 HttpClientFactory (Part 2) 定义命名化和类型化的客户端
    Asp.net Core 2.0 OpenId Connect Handler缺失Claims?
  • 原文地址:https://www.cnblogs.com/zhangweizhong/p/6225196.html
Copyright © 2011-2022 走看看