Web Api 之 404 Resource Not Found 錯誤消息封裝


問題背景

最近在重構個以前做過的一個電商網站,做了很大的改動,主要是性能和穩定性。以后有機會詳細討論。

目前在基於Web Api開發API項目,供APP及移動站點使用。使用Asp.Net Web Api開發方便快捷毋庸多言,誰用誰知道,呵呵~~~

Web Api技術知道日久,基本也知道怎么回事,畢竟在使用上跟Asp.Net MVC使用比較相似。但是真正在開發的時候,還是大大小小碰到不少問題,也有挺多心得。如題問題即使其中的惡一個。如果時間足夠,我將一一跟各位分享和討論。針對某個問題,我的方案有錯誤或者您有更好的方案,也請不吝賜教。小弟在此謝過!!

問題

廢話不多說,直接討論本問題。在處理返回消息的時候,希望將返回的消息都進行統一。消息格式如:

response:
{
   head:{
   status: 200 //(200: ok, 404: 找不到方法/Action/controller, 500: 內部錯誤),
   errors: 錯誤信息
   }
   body: 具體返回數據
}

對於正常的Action返回的數據,有許多方式可以處理成我們所需要的格式,若有需要以后再開一貼單獨討論。但對於404錯誤,也就是找不到Action或者Controller的錯誤,就不是那么好處理。因為請求不會進入Action通道里,也就是Filter也夠不到,無法攔截。

解決方案

首先想到的解決方案是在Application_Error事件里進行處理。但是通過實際的試驗,發現此事件並不會觸發,就算觸發了,也沒法將我們需要的標准數據格式返回到客戶端來。

之后想到的方法,是在請求管道進行攔截處理。但是本人對WebApi研究不深,更何況是深奧的請求管道。在看了些資料和嘗試之后,以失敗告終。由於時間關系,只能放棄此方式。至於WebApi的請求管道,只能留待以后再細細研究。

無奈知曉,只能去網上繼續查找看是否有現成方案。花費大量時間之后,依然沒發現一個中文的解決方案。無奈只能求助於國外的資料。要說,還是國外資料全,沒費多少時間,就找到一個方案。鏈接地址:http://weblogs.asp.net/imranbaloch/handling-http-404-error-in-asp-net-web-api

此方案的關鍵是繼承ApiControllerActionSelector和DefaultHttpControllerSelector兩個Selector類,嘗試獲取匹配請求的Controller和Action。若獲取不到,則說明沒有對應的Action和Controller。此時,將Action重定向到執行錯誤處理Action。請看具體實現代碼。

1.嘗試獲取匹配請求的Controller和Action

public override HttpActionDescriptor SelectAction(HttpControllerContext controllerContext)
        {
            HttpActionDescriptor decriptor = null;
            try
            {
                decriptor = base.SelectAction(controllerContext);
            }
            catch (HttpResponseException ex)
            {
                var code = ex.Response.StatusCode;
                if (code != HttpStatusCode.NotFound && code != HttpStatusCode.MethodNotAllowed)
                    throw;
                var routeData = controllerContext.RouteData;
                routeData.Values["action"] = "Handle404";
                IHttpController httpController = new ErrorController();
                controllerContext.Controller = httpController;
                controllerContext.ControllerDescriptor = new HttpControllerDescriptor(controllerContext.Configuration, "Error", httpController.GetType());
                decriptor = base.SelectAction(controllerContext);
            }
            return decriptor;
        }
    }

    public class NotFoundControllerSelector : DefaultHttpControllerSelector
    {
        public NotFoundControllerSelector(HttpConfiguration configuration)
            : base(configuration)
        {
        }

        public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
        {
            HttpControllerDescriptor decriptor = null;
            try
            {
                decriptor = base.SelectController(request);
            }
            catch (HttpResponseException ex)
            {
                var code = ex.Response.StatusCode;
                if (code != HttpStatusCode.NotFound)
                    throw;
                var routeValues = request.GetRouteData().Values;
                routeValues["controller"] = "Error";
                routeValues["action"] = "Handle404";
                decriptor = base.SelectController(request);
            }
            return decriptor;
        }
    }

2.在WebApiConfig中注冊此二Selector

 config.Services.Replace(typeof (IHttpControllerSelector), new NotFoundControllerSelector(config));
 config.Services.Replace(typeof(IHttpActionSelector), new NotFoundActionSelector());

3.添加處理錯誤的Route,請務必將此路由注冊在所有路由的最后。

config.Routes.MapHttpRoute(
                name: "Error404",
                routeTemplate: "{*url}",
                defaults: new { controller = "Error", action = "Handle404" }
            );

4.創建處理錯誤的Controller和Action。

public class ErrorController : ApiController
    {
        [HttpGet, HttpPost, HttpPut, HttpDelete, HttpHead, HttpOptions, AcceptVerbs("PATCH")]
        public ResultModel Handle404()
        {
            return new ResultModel() //ResultModel是本人創建的標准返回結果實體
            {
                head = new ResultHeaderModel() {status = HttpStatusCode.NotFound, errors = "Route not found"}
            };
        }
    }

5.測試程序,返回結果如預期。

本文到此結束,代碼比較清晰,看即懂,恕不贅述。

若給位對本文有什么疑問或者建議,郁或者有其他方案,歡迎大家討論。小弟在此謝過~~~


免責聲明!

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



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