如何让 Web API 统一回传格式以及例外处理
1个回答
2016-06-24
展开全部
当我们在开发WebAPI时,一般的情况下每个API回传的数据型态或格式都不尽相同,如果你的项目从头到尾都是由你一个人独力完成,那也许还可以说声「阿密陀佛」,但如果是有其他人需要和你共享你的Api,而回传的数据格式又不一样,相信是会增加使用者的困扰,也大大增加了程序的复杂度与维护上的难度。所以本篇也纪录一下自己在实作上的经验,一方面留个纪录也希望帮助人,废物不多说我们开始吧!了解架构并实作原本在找数据时找到这篇使用Asp.NetMVC打造WebApi(16)–统一输入/出格式以及异常处理策略,不过发现里面的所用到的方法似乎是ForASP.NETMVC,而非WebAPI(不知道笔者这样认知有没有错误,如果有还麻烦前辈们指教),而本篇的思考模式跟这篇是一样的,只是把它改成WebAPI能用的方法而已。[]按照上图所示当使用者请求不同的API时,返回页面之前会将数据重新打包后再传回页面给使用者,如此一来用户所看到的数据格式就会是固定的。1.所以首先我们需要先自定义一个Model来当作我们的包装的容器,其类别的定义如下:publicclassApiResultModel{publicHttpStatusCodeStatus{get;set;}publicobjectData{get;set;}publicstringErrorMessage{get;set;}}2.相信写过ASP.NETMVC的朋友一定会知道,一般我们会将一些在Action中固定的逻辑,利用Filter来套用到每一个Action上面,例如:Authorize。如果你对Filter不是很熟悉可以参考一下网络上前辈所写的文章:[VS2010]ASP.NETMVCwithActionFilters。所以这边我们也需要使用同样的技巧来重新打包我们回传的数据格式,我们先新增一个ApiResultAttribute.cs的档案,且继承System.Web.Http.Filters.ActionFilterAttribute,并且复写OnActionExecuted的方法,如下:publicclassApiResultAttribute:System.Web.Http.Filters.ActionFilterAttribute{publicoverridevoidOnActionExecuted(HttpActionExecutedContextactionExecutedContext){base.OnActionExecuted(actionExecutedContext);}}3.而OnActionExecuted会在Action执行之后呼叫,也表示我们将资料送进这个方法里面,接着处理我们主要打包的程序逻辑,程序代码如下:publicoverridevoidOnActionExecuted(HttpActionExecutedContextactionExecutedContext){base.OnActionExecuted(actionExecutedContext);ApiResultModelresult=newApiResultModel();//取得由API返回的状态代码result.Status=actionExecutedContext.ActionContext.Response.StatusCode;//取得由API返回的资料result.Data=actionExecutedContext.ActionContext.Response.Content.ReadAsAsync().Result;//重新封装回传格式actionExecutedContext.Response=actionExecutedContext.Request.CreateResponse(result.Status,result);}4.而为了要让所有的WebAPI都能套用我们自定义的Filter,所以我们需要到App_Start→WebApiConfig.cs→Register来注册全局的WebAPIFilter。(注意:若要注册WebAPI的Filter需在WebApiConfig.cs中注册,而非FilterConfig.cs中)config.Filters.Add(newApiResultAttribute());5.重新建置之后我们再重新执行一次原先的WebAPI程序,就会看到回传的格式已经变成我们自定义的格式了:"Status":200,"Data":[{"Account":"taxi","Mark":"","Name":"王大明","Telephone":"0986540123","AccountStatus":true},{"Account":"taxi2","Mark":"","Name":"方大同","Telephone":"0922335111","AccountStatus":true},{"Account":"q121234567","Mark":null,"Name":"0000","Telephone":"0972334334","AccountStatus":true}],"ErrorMessage":null例外处理前面我们已经将讯息打包成我们要的格式了,不过我们还没确切地去处理有关例外的程序代码,一般当程序发生错误产生例外时,我们当然也希望接收端能知道程序发生错误,进而显示该显示的讯息,而不是活生生地看着程序Crash或是停顿,这样将带给你的客户不好的体验,而在ASP.NETMVC中也有提供专门处理例外的ExceptionFilterAttribute,所以接着来看看该如何打包我们的例外讯息吧。1.新增一个ApiErrorHandleAttribute.cs并且继承System.Web.Http.Filters.ExceptionFilterAttribute,接着复写OnException当例外发生时执行的方法,程序代码如下:publicclassApiErrorHandleAttribute:System.Web.Http.Filters.ExceptionFilterAttribute{publicoverridevoidOnException(System.Web.Http.Filters.HttpActionExecutedContextactionExecutedContext){base.OnException(actionExecutedContext);}}2.透过OnException的方法能让我们捕捉当例外发生时要处理的事情,一般系统我们也会在这边将发生错误的时间、登入的用户以及错误的状况记录下来(例如:系统事件、存入数据库、写入.txt档…等),不过这边不是我们讨论的重点,我们先来看看该如何打包我们的例外讯息,程序代码如下:publicoverridevoidOnException(System.Web.Http.Filters.HttpActionExecutedContextactionExecutedContext){base.OnException(actionExecutedContext);//取得发生例外时的错误讯息varerrorMessage=actionExecutedContext.Exception.Message;varresult=newApiResultEntity(){Status=HttpStatusCode.BadRequest,ErrorMessage=errorMessage};//重新打包回传的讯息actionExecutedContext.Response=actionExecutedContext.Request.CreateResponse(result.Status,result);}3.而因为程序丢出例外后会先回到OnActionExcuted在进到例外的处理,所以我们稍微修改一下原本的OnActionExcuted这个方法,让发生例外时就直接跳过不再这边打包我们的讯息,程序代码如下:publicoverridevoidOnActionExecuted(HttpActionExecutedContextactionExecutedContext){//若发生例外则不在这边处理if(actionExecutedContext.Exception!=null)return;base.OnActionExecuted(actionExecutedContext);ApiResultModelresult=newApiResultModel();//取得由API返回的状态代码result.Status=actionExecutedContext.ActionContext.Response.StatusCode;//取得由API返回的资料result.Data=actionExecutedContext.ActionContext.Response.Content.ReadAsAsync().Result;//重新封装回传格式actionExecutedContext.Response=actionExecutedContext.Request.CreateResponse(result.Status,result);}3.接着我们一样要将此自定义的Filter注册到程序当中,所以一样到App_Start→WebApiConfig.cs→Register来注册我们的Filter:config.Filters.Add(newApiErrorHandleAttribute());4.重新建置后,当我们程序发生例外时也会依照我们的格式回传给使用者:{"Status":400,"Data":null,"ErrorMessage":"尝试以零除。"}总结就这样我们又成功解决了一个简单的案例,不过这边也需要提醒一下读者,一般在处理例外这边是不会直接将例外讯息回传给用户的,因为如果假设你今天丢出的例外有包含了一些比较敏感的信息,例如:数据库名称或数据表名称…等等,这样一来你的程序就间接的有了漏洞了,所以如果真的要用此程序代码记得后面例外捕捉那边还要在包装一下。
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询