[Web API] 如何让 Web API 统一回传格式以及例外处理

前言

当我们在开发 Web API 时,一般的情况下每个 API 回传的数据型态或格式都不尽相同,如果你的项目从头到尾都是由你一个人独力完成,那也许还可以说声「阿密陀佛」,但如果是有其他人需要和你共享你的 Api ,而回传的数据格式又不一样,相信是会增加使用者的困扰,也大大增加了程序的复杂度与维护上的难度。所以本篇也纪录一下自己在实作上的经验,一方面留个纪录也希望帮助更多人,废物不多说我们开始吧!

了解架构并实作

原本在找数据时找到这篇 使用Asp.NET MVC打造Web Api (16) – 统一输入/出格式以及异常处理策略,不过发现里面的所用到的方法似乎是 For ASP.NET MVC,而非 Web API (不知道笔者这样认知有没有错误,如果有还麻烦前辈们指教),而本篇的思考模式跟这篇是一样的,只是把它改成 Web API 能用的方法而已。

[]

按照上图所示当使用者请求不同的 API 时,返回页面之前会将数据重新打包后再传回页面给使用者,如此一来用户所看到的数据格式就会是固定的。

1.所以首先我们需要先自定义一个 Model 来当作我们的包装的容器,其类别的定义如下:

{
    public HttpStatusCode Status { get; set; }
    public object Data { get; set; }
    public string ErrorMessage { get; set; }
2.相信写过 ASP.NET MVC 的朋友一定会知道,一般我们会将一些在 Action 中固定的逻辑,利用 Filter 来套用到每一个
Action 上面,例如:Authorize。如果你对 Filter 不是很熟悉可以参考一下网络上前辈所写的文章:[VS2010]
ASP.NET MVC with Action Filters。 所以这边我们也需要使用同样的技巧来重新打包我们回传的数据格式,我们先新增一个
ApiResultAttribute.cs 的档案,且继承
System.Web.Http.Filters.ActionFilterAttribute,并且复写
OnActionExecuted 的方法,如下:
{
       {
            base.OnActionExecuted(actionExecutedContext);     
}

3.而 OnActionExecuted 会在 Action 执行之后呼叫,也表示我们将资料送进这个方法里面,接着处理我们主要打包的程序逻辑,程序代码如下:

{
    base.OnActionExecuted(actionExecutedContext);
 
    ApiResultModel result = new ApiResultModel();
 
    result.Status = actionExecutedContext.ActionContext.Response.StatusCode;
    result.Data = actionExecutedContext.ActionContext.Response.Content.ReadAsAsync<object>().Result;
    actionExecutedContext.Response = actionExecutedContext.Request.CreateResponse(result.Status, result);
4.而为了要让所有的 Web API 都能套用我们自定义的 Filter,所以我们需要到 App_Start → WebApiConfig.cs
→ Register 来注册全局的 Web API Filter。(注意:若要注册 Web API 的 Filter 需在
WebApiConfig.cs 中注册,而非 FilterConfig.cs 中)
config.Filters.Add(new ApiResultAttribute());

5.重新建置之后我们再重新执行一次原先的 Web API 程序,就会看到回传的格式已经变成我们自定义的格式了:

    "Data": [
            "Account": "taxi",
            "Name": "王大明",
            "AccountStatus": true
        {
            "Mark": "",
            "Telephone": "0922335111",
        },
            "Account": "q121234567",
            "Name": "0000",
            "AccountStatus": true
    ],
例外处理

前面我们已经将讯息打包成我们要的格式了,不过我们还没确切地去处理有关例外的程序代码,一般当程序发生错误产生例外时,我们当然也希望接收端能知道程序发生错误,进而显示该显示的讯息,而不是活生生地看着程序 Crash 或是停顿,这样将带给你的客户不好的体验,而在 ASP.NET MVC 中也有提供专门处理例外的 ExceptionFilterAttribute,所以接着来看看该如何打包我们的例外讯息吧。

1.新增一个 ApiErrorHandleAttribute.cs 并且继承 System.Web.Http.Filters.ExceptionFilterAttribute,接着复写 OnException 当例外发生时执行的方法,程序代码如下:

{
       {
           base.OnException(actionExecutedContext);
}

2.透过 OnException 的方法能让我们捕捉当例外发生时要处理的事情,一般系统我们也会在这边将发生错误的时间、登入的用户以及错误的状况记录下来 (例如:系统事件、存入数据库、写入 .txt 档 … 等),不过这边不是我们讨论的重点,我们先来看看该如何打包我们的例外讯息,程序代码如下:

{
    base.OnException(actionExecutedContext);
    // 取得发生例外时的错误讯息
    var errorMessage = actionExecutedContext.Exception.Message;
 
    {
        ErrorMessage = errorMessage
    };
 
    actionExecutedContext.Response = actionExecutedContext.Request
        .CreateResponse(result.Status, result);
 

3.而因为程序丢出例外后会先回到 OnActionExcuted 在进到例外的处理,所以我们稍微修改一下原本的 OnActionExcuted 这个方法,让发生例外时就直接跳过不再这边打包我们的讯息,程序代码如下:

{
    if (actionExecutedContext.Exception != null)
    return;
    base.OnActionExecuted(actionExecutedContext);
 
    ApiResultModel result = new ApiResultModel();
 
    result.Status = actionExecutedContext.ActionContext.Response.StatusCode;
    result.Data = actionExecutedContext.ActionContext.Response.Content.ReadAsAsync<object>().Result;
    actionExecutedContext.Response = actionExecutedContext.Request.CreateResponse(result.Status, result);
3.接着我们一样要将此自定义的 Filter 注册到程序当中,所以一样到 App_Start → WebApiConfig.cs → Register 来注册我们的 Filter:
config.Filters.Add(new ApiErrorHandleAttribute());

4.重新建置后,当我们程序发生例外时也会依照我们的格式回传给使用者:

    "Status": 400,
    "ErrorMessage": "尝试以零除。"
总结

就这样我们又成功解决了一个简单的案例,不过这边也需要提醒一下读者,一般在处理例外这边是不会直接将例外讯息回传给用户的,因为如果假设你今天丢出的例外有包含了一些比较敏感的信息,例如:数据库名称或数据表名称…等等,这样一来你的程序就间接的有了漏洞了,所以如果真的要用此程序代码记得后面例外捕捉那边还要在包装一下。

[Web API] 如何让 Web API 统一回传格式以及例外处理的更多相关文章

  1. [Web API] 如何让 Web API 统一回传格式以及例外处理[转]

    [Web API] 如何让 Web API 统一回传格式以及例外处理 前言 当我们在开发 Web API 时,一般的情况下每个 API 回传的数据型态或格式都不尽相同,如果你的项目从头到尾都是由你一个 ...

  2. 【ASP.NET Web API2】初识Web API

    Web Api 是什么? MSDN:ASP.NET Web API 是一种框架,用于轻松构建可以访问多种客户端(包括浏览器和移动设备)的 HTTP 服务 百度百科:Web API是网络应用程序接口. ...

  3. Request Entity Too Large for Self Hosted ASP.Net Web API在Selfhost的api后台怎么解决Request Entity Too Large问题

    Request Entity Too Large for Self Hosted ASP.Net Web API在Selfhost的api后台怎么解决Request Entity Too Large问 ...

  4. ASP.NET Web API与Rest web api(一)

    HTTP is not just for serving up web pages. It is also a powerful platform for building APIs that exp ...

  5. ASP.NET Web API与Rest web api(一)

    本文档内容大部分来源于:http://www.cnblogs.com/madyina/p/3381256.html HTTP is not just for serving up web pages. ...

  6. jboss7 Java API for RESTful Web Services (JAX-RS) 官方文档

    原文:https://docs.jboss.org/author/display/AS7/Java+API+for+RESTful+Web+Services+(JAX-RS) Content Tuto ...

  7. Web服务器Raspkate的RESTful API

    基于轻量型Web服务器Raspkate的RESTful API的实现 在上一篇文章中,我们已经了解了Raspkate这一轻量型Web服务器,今天,我们再一起了解下如何基于Raspkate实现简单的RE ...

  8. ASP.NET MVC Web API 学习笔记---Web API概述及程序示例

    1. Web API简单说明 近来很多大型的平台都公开了Web API.比如百度地图 Web API,做过地图相关的人都熟悉.公开服务这种方式可以使它易于与各种各样的设备和客户端平台集成功能,以及通过 ...

  9. web API简介(一):API,Ajax和Fetch

    概述 今天逛MDN,无意中看到了web API简介,觉得挺有意思的,就认真读了一下. 下面是我在读的时候对感兴趣的东西的总结,供自己开发时参考,相信对其他人也有用. 什么是API API (Appli ...

随机推荐

  1. Linux之vi/vim命令

    vi命令是linux中必不可少的一个编辑器工具.那么vi与vim又有什么区别呢,可以简单理解为vim是vi的升级版.在编辑一个文本时,vi不会显示颜色,而vim会显示颜色.显示颜色更易于用户进行编辑, ...

  2. Ossec常用命令

    启动并查看httpd服务 systemctl start httpd systemctl status httpd.service 启动并查看mysql服务 systemctl start maria ...

  3. 8、双向一对多的关联关系(等同于双向多对一。1的一方有对n的一方的集合的引用,同时n的一方有对1的一方的引用)

    双向一对多关联关系 “双向一对多关联关系”等同于“双向多对一关联关系”:1的一方有对n的一方的集合的引用,同时n的一方有对1的一方的引用. 还是用客户Customer和订单Order来解释: “一对多 ...

  4. 使用 Async 和 Await 的异步编程

    来自:http://msdn.microsoft.com/library/vstudio/hh191443   异步对可能起阻止作用的活动(例如,应用程序访问 Web 时)至关重要. 对 Web 资源 ...

  5. linux协议栈部分资料

    socket实现:http://blog.csdn.net/zhangskd(含有tcp/ip专栏) http://blog.chinaunix.net/uid-20528014-id-90573.h ...

  6. 怎么在eclipse里调试WebDriver的源代码

    当你看完WebDriver的工作原理这篇博客以后,是不是也跃跃欲试想印证文章里的理论是不是正确,想自己也看下webdriver的源代码,并且调试下,通过代码来更深入的了解WebDriver的工作原理. ...

  7. 成为一个PHP专家:缺失的环节

    这一篇文章是“Becoming a PHP Professional”系列 4 篇博文中的第 1 篇. 当浏览各类与PHP相关的博客时,比如Quora上的问题,谷歌群组,简讯和杂志,我经常注意到技能的 ...

  8. Linux文件与进程的Capability简介

    UID这种权限机制颗粒太粗,容易引起权利过剩(溢出),Linux引入了Capability:每个Capability系统内以一位Bit代表,OS内部使用64bit存储. 下面是android的capa ...

  9. iOS学习笔记:frame,bound,center, anchorPoint

    frame: View在它的Super View坐标系里的坐标 bound: 用来定义View自身坐标系和边界的Rect,Rect的原点表示View自身坐标系的原点坐标.举个例子: 一般情况下boun ...

  10. Android中LayoutInflater的使用

    Inflater英文意思是膨胀,在Android中应该是扩展的意思吧. LayoutInflater 的作用类似于 findViewById(),不同点是LayoutInflater是用来找layou ...