Web API應用架構在Winform混合框架中的應用(2)--自定義異常結果的處理


在上篇隨筆《Web API應用架構在Winform混合框架中的應用(1)》中我介紹了關於如何在Winfrom里面整合WebAPI,作為一個新型數據源的接入方式,從而形成了三種不同的數據提供來源,前文在介紹整體性框架方面,着筆較多,注重整合的統一性,但是在Web API方面還不算很具體,本系列將繼續這個主題,介紹Web API開發中常見到的一些問題,對其中各個技術要點進行總結,本文主要介紹Web API自定義異常結果的處理。

1、常規的異常處理

統一的異常處理,把正確的信息返回給調用者很重要,可以讓接口開發人員或者用戶,了解具體的原因所在,這樣可以得到有效的錯誤處理。

參考微信API的處理,微信API,對於調用都有一個錯誤信息返回,不會直接裸露未經處理的異常,因此它們都是經過了一定的攔截處理,然后把錯誤信息包裝提供給接口調用方的。如下是微信的一些接口處理錯誤。

錯誤時微信會返回錯誤碼等信息,JSON數據包示例如下(該示例為AppID無效錯誤):

{"errcode":40013,"errmsg":"invalid appid"}

我們根據自己的需要,定義了一個統一的錯誤信息實體類,如下所示。

    /// <summary>
    /// 接口返回的錯誤信息
    /// </summary>
    public class BaseResultJson
    {
        /// <summary>
        /// 錯誤代碼
        /// </summary>
        public int errcode { get; set; }

        /// <summary>
        /// 如果不成功,返回的錯誤信息
        /// </summary>
        public string errmsg { get; set; }

        /// <summary>
        /// 是否成功
        /// </summary>
        public bool success { get; set; }
    }

這樣我們就可以把攔截到的錯誤信息,轉換為這樣一個方便使用的實體類信息了。

攔截Web API的調用異常,一般可以結合Try Catch的方法,以及異常攔截器進行處理,如下是主動拋出的一些異常信息處理。

            //如果沒有通過,則拋出異常,由異常過濾器統一處理
            if (!result.success)
            {
                throw new MyApiException(result.errmsg, result.errcode);
            }

其中MyApiException是自定義的一個異常信息,用來承載自定義錯誤信息的異常類。

異常攔截器,我們在Web API里面可以通過Attribute這種標簽特性進行處理,如下是我在Web API的基類里面定義了一個異常處理器。

    /// <summary>
    /// 所有接口基類
    /// </summary>

    [ExceptionHandling]
    public class BaseApiController : ApiController

這個特性對象的定義,它的代碼如下所示。

    /// <summary>
    /// API自定義錯誤過濾器屬性
    /// </summary>
    public class ExceptionHandlingAttribute : ExceptionFilterAttribute
    {
        /// <summary>
        /// 統一對調用異常信息進行處理,返回自定義的異常信息
        /// </summary>
        /// <param name="context">HTTP上下文對象</param>
        public override void OnException(HttpActionExecutedContext context)
        {
            //自定義異常的處理
            MyApiException ex = context.Exception as MyApiException;
            if (ex != null)
            {                
                throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.InternalServerError)
                {
                    //封裝處理異常信息,返回指定JSON對象
                    Content = new StringContent(new BaseResultJson(ex.Message, false, ex.errcode).ToJson()),
                    ReasonPhrase = "Exception"
                });

            }

            //記錄關鍵的異常信息
            Debug.WriteLine(context.Exception);
            
            //常規異常的處理
            string msg = string.IsNullOrEmpty(context.Exception.Message) ? "接口出現了錯誤,請重試或者聯系管理員" : context.Exception.Message;
            throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.InternalServerError)
            {
                Content = new StringContent(msg),
                ReasonPhrase = "Critical Exception"
            });
        }
    }

根據這些代碼,我們就可以實現對調用異常的統一封裝處理,讓它給我們返回統一的對象信息了,如下是其中一個調用異常,轉換為自定義異常信息后的結果輸出。

{"errcode":404,"errmsg":"請求的資源不支持 http 方法“POST”。","success":false}

這樣我們在處理Web API的返回結果的時候,可以先處理它的異常信息,具體的處理代碼如下所示。

            HttpHelper helper = new HttpHelper();
            helper.ContentType = "application/json";

            string content = helper.GetHtml(url, postData, true);
            VerifyErrorCode(content);

            T result = JsonConvert.DeserializeObject<T>(content);
            return result;

我們在上面紅色部分的代碼就是先處理異常定義信息,如果有這些異常,我們可以在界面中進行異常處理顯示了。

例如,如果自定義異常存在,我們轉換后,把對應的信息顯示出來,重新拋出異常即可。

                BaseResultJson errorResult = JsonConvert.DeserializeObject<BaseResultJson>(content);
                //非成功操作才記錄異常,因為有些操作是返回正常的結果({"errcode": 0, "errmsg": "ok"})
                if (errorResult != null && !errorResult.success)
                {
                    string error = string.Format("請求發生錯誤!錯誤代碼:{0},說明:{1}", (int)errorResult.errcode, errorResult.errmsg);
                    LogTextHelper.Error(errorResult.ToJson());

                    throw new Exception(error);//拋出錯誤
                }

 

2、地址接口異常處理

對於常規的異常,我們通過上面的處理方式,就可以很好進行攔截並處理了,如果接口異常是全局性的,如訪問地址簿正確,或者參數多了幾個信息,那么調用的接口就不是有效的地址,這樣的話,返回的信息就不會被上面的攔截器進行處理了。

如我們給一個無效的API調用路徑,在瀏覽器中獲得下面錯誤結果。

上面結果就無法被我們的常規異常攔截器所捕獲,因此不會輸出經過封裝好的異常信息。

如果需要攔截,我們需要增加自己的消息代理處理,用來捕獲這些特殊的異常信息。

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

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

上面紅色部分就是我們自己添加的消息代理處理類,用來處理一些特殊的異常信息,如下代碼所示。

    /// <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(new BaseResultJson(error.Message, false, 404).ToJson()),
                        ReasonPhrase = "Exception"
                    });
                }
                else
                {
                    return response;
                }
            });
        }
    }

經過了上面的處理后,我們進一步測試一下不存在的地址的異常處理結果,可以看到輸出的內容是經過了自定義對象的轉換了。

常規的調用,如果接口不對應,那么錯誤也是類似下面的消息

{"errcode":404,"errmsg":"找不到與請求 URI“http://localhost:9001/api/SystemType/Delete?signature=72f8d706c79dc14d70fc3f080d4706748d754021&timestamp=1443194061&nonce=0.650359861855563&appid=website_9A39C2A8&token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiIxIiwiaWF0IjoxNDQzMTk0MDM4LCJqdGkiOiI1YmEyYmE5Ni0yZTA4LTQ1ZTgtYTAwNy01MmY3OTkzYTg2NzEiLCJuYW1lIjoiYWRtaW4iLCJjaGFubmVsIjoiMCIsInNoYXJlZGtleSI6IjEyMzRhYmNkIn0.RRXQmmSCJzDK5Or6rmBL5wjd-YIJoEQFc0pOzqhR6IU”匹配的 HTTP 資源。","success":false}

有了這些信息,我們就可以統一我們的調用規則,並進行異常記錄和顯示了,非常方便。

 

 系列文章如下所示:

Web API應用架構在Winform混合框架中的應用(1)

Web API應用架構在Winform混合框架中的應用(2)--自定義異常結果的處理

Web API接口設計經驗總結 

Web API應用架構在Winform混合框架中的應用(3)--Winfrom界面調用WebAPI的過程分解

 Web API應用架構在Winform混合框架中的應用(4)--利用代碼生成工具快速開發整套應用


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM