一.服务器出现异常,会统一向客户端返回 500 的错误.
[RoutePrefix("api/test")] public class TestController : ApiController { public IHttpActionResult Get() { throw new Exception("出错了!"); } }
二.全局过滤器
1.在 App_Start 里面新建一个全局过滤器
public class MyExceptionFilterAttribute : ExceptionFilterAttribute { public override void OnException(HttpActionExecutedContext actionExecutedContext) { //设置返回的HTTP状态码为 Bad Request 即 400 actionExecutedContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.BadRequest) { //设置返回的异常内容 Content = new StringContent(actionExecutedContext.Exception.Message) }; base.OnException(actionExecutedContext); } }
2.在 Global.asax 里面的 Application_Start 方法中添加该全局过滤器
public class WebApiApplication : System.Web.HttpApplication { protected void Application_Start() { GlobalConfiguration.Configure(WebApiConfig.Register); //添加全局过滤器 GlobalConfiguration.Configuration.Filters.Add(new MyExceptionFilterAttribute()); } }
测试结果:
三.Action 过滤器
[RoutePrefix("api/test")] public class TestController : ApiController { public IHttpActionResult Get() { throw new Exception("出错了!"); } //将自定义过滤器特性加在action上 [MyExceptionFilter] public IHttpActionResult Post() { throw new Exception("怎么又出错了!"); } }
同时注释这行代码 //GlobalConfiguration.Configuration.Filters.Add(new MyExceptionFilterAttribute());
测试结果:
四.Controller 过滤器
原理同 Action 过滤器
五.自定义异常信息
public void Get() { throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.Unauthorized) { Content = new StringContent("哈哈,猪啊"), ReasonPhrase = "pig" }); }
六.地址接口异常处理
对于常规的异常,我们通过上面的处理方式,就可以很好进行拦截并处理了,如果接口异常是全局性的,如访问地址簿正确,或者参数多了几个信息,那么调用的接口就不是有效的地址,这样的话,返回的信息就不会被上面的拦截器进行处理了。
如我们给一个无效的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×tamp=1443194061&nonce=0.650359861855563&appid=website_9A39C2A8&token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiIxIiwiaWF0IjoxNDQzMTk0MDM4LCJqdGkiOiI1YmEyYmE5Ni0yZTA4LTQ1ZTgtYTAwNy01MmY3OTkzYTg2NzEiLCJuYW1lIjoiYWRtaW4iLCJjaGFubmVsIjoiMCIsInNoYXJlZGtleSI6IjEyMzRhYmNkIn0.RRXQmmSCJzDK5Or6rmBL5wjd-YIJoEQFc0pOzqhR6IU”匹配的 HTTP 资源。","success":false}
有了这些信息,我们就可以统一我们的调用规则,并进行异常记录和显示了,非常方便。
补充:
public override void OnException(HttpActionExecutedContext actionExecutedContext) { //设置返回的HTTP状态码为 Bad Request 即 400 actionExecutedContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.BadRequest) { //设置返回的异常内容 Content = new StringContent(actionExecutedContext.Exception.Message), ReasonPhrase = "hello world" }; base.OnException(actionExecutedContext); }
注意这个 hello world