zoukankan      html  css  js  c++  java
  • 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.测试程序,返回结果如预期。

    本文到此结束,代码比较清晰,看即懂,恕不赘述。

    若给位对本文有什么疑问或者建议,郁或者有其他方案,欢迎大家讨论。小弟在此谢过~~~

  • 相关阅读:
    【C/C++开发】TinyXml操作(含源码下载)
    【C/C++开发】TinyXml操作(含源码下载)
    【计算机视觉】目标检测中的指标衡量Recall与Precision
    【计算机视觉】目标检测中的指标衡量Recall与Precision
    【图像处理】关于掩模的作用
    【图像处理】关于掩模的作用
    【神经网络与深度学习】【计算机视觉】YOLO2
    【神经网络与深度学习】【计算机视觉】YOLO2
    【神经网络与深度学习】【计算机视觉】SSD
    【神经网络与深度学习】【计算机视觉】SSD
  • 原文地址:https://www.cnblogs.com/focuscode/p/4896338.html
Copyright © 2011-2022 走看看