如何友好的處理 WebApi 中拋出的錯(cuò)誤
本文轉(zhuǎn)載自微信公眾號(hào)「碼農(nóng)讀書」,作者碼農(nóng)讀書。轉(zhuǎn)載本文請(qǐng)聯(lián)系碼農(nóng)讀書公眾號(hào)。
微軟的 ASP.NET Web API 是一個(gè)輕量級(jí)的web框架,可用來(lái)構(gòu)建基于 http 無(wú)狀態(tài)的rest服務(wù),異常是一種運(yùn)行時(shí)錯(cuò)誤,異常處理是一種處理運(yùn)行時(shí)錯(cuò)誤的技術(shù),每一個(gè)開發(fā)者都應(yīng)該知道如何處理 Web API 中的異常,并且在 Action 中使用合適的 錯(cuò)誤碼 和 錯(cuò)誤信息 進(jìn)行包裝。
WebAPI 中的 HttpResponseException
你可以在 Action 中使用 HttpResponseException 來(lái)包裝指定的 HttpCode 和 HttpMessage,如下例子所示:
- public Employee GetEmployee(int id)
- {
- Employee emp = employeeRepository.Get(id);
- if (emp == null)
- {
- var response = new HttpResponseMessage(HttpStatusCode.NotFound)
- {
- Content = new StringContent("Employee doesn't exist", System.Text.Encoding.UTF8, "text/plain"),
- StatusCode = HttpStatusCode.NotFound
- }
- throw new HttpResponseException(response);
- }
- return emp;
- }
如果你的 Action 返回的是 IHttpActionResult,那么可將 GetEmployee() 方法修改如下:
- public IHttpActionResult GetEmployee(int id)
- {
- Employee emp = employeeRepository.Get(id);
- if (emp == null)
- {
- var response = new HttpResponseMessage(HttpStatusCode.NotFound)
- {
- Content = new StringContent("Employee doesn't exist", System.Text.Encoding.UTF8, "text/plain"),
- StatusCode = HttpStatusCode.NotFound
- }
- throw new HttpResponseException(response);
- }
- return Ok(emp);
- }
從上面的代碼可以看出,錯(cuò)誤碼 和 錯(cuò)誤消息 都賦給了 Response 對(duì)象,然后包裝到了 HttpResponseException 進(jìn)行返回。
WebAPI 中使用 HttpError
除了直接實(shí)例化 HttpResponseMessage 類,還可以使用 Request.CreateErrorResponse() 快捷的創(chuàng)建 HttpResponseMessage 類,如下代碼所示:
- public IActionResult GetEmployee(int id)
- {
- Employee emp = employeeRepository.Get(id);
- if (emp == null)
- {
- string message = "Employee doesn't exist";
- throw new HttpResponseException(
- Request.CreateErrorResponse(HttpStatusCode.NotFound, message));
- }
- return Ok(emp);
- }
WebAPI 中使用 異常過(guò)濾器
異常過(guò)濾器是一種可以在 WebAPI 中捕獲那些未得到處理的異常的過(guò)濾器,要想創(chuàng)建異常過(guò)濾器,你需要實(shí)現(xiàn) IExceptionFilter 接口,不過(guò)這種方式比較麻煩,更快捷的方法是直接繼承 ExceptionFilterAttribute 并重寫里面的 OnException() 方法即可,這是因?yàn)?ExceptionFilterAttribute 類本身就實(shí)現(xiàn)了 IExceptionFilter 接口,如下代碼所示:
- [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
- public abstract class ExceptionFilterAttribute : FilterAttribute, IExceptionFilter, IFilter
- {
- protected ExceptionFilterAttribute();
- public virtual void OnException(HttpActionExecutedContext actionExecutedContext);
- public virtual Task OnExceptionAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken);
- }
下面的代碼片段展示了如何通過(guò)重寫 ExceptionFilterAttribute.OnException() 方法來(lái)創(chuàng)建一個(gè)自定義異常過(guò)濾器,請(qǐng)注意下面的代碼是如何捕獲在 Action 中拋出的異常,并將捕獲到的異常轉(zhuǎn)換為 HttpStatusResponse 實(shí)體,然后塞入合適的 httpcode 和 httpmessage,如下代碼所示:
- public class CustomExceptionFilter : ExceptionFilterAttribute
- {
- public override void OnException(HttpActionExecutedContext actionExecutedContext)
- {
- HttpStatusCode status = HttpStatusCode.InternalServerError;
- String message = String.Empty;
- var exceptionType = actionExecutedContext.Exception.GetType();
- if (exceptionType == typeof(UnauthorizedAccessException))
- {
- message = "Access to the Web API is not authorized.";
- status = HttpStatusCode.Unauthorized;
- }
- else if (exceptionType == typeof(DivideByZeroException))
- {
- message = "Internal Server Error.";
- status = HttpStatusCode.InternalServerError;
- }
- else
- {
- message = "Not found.";
- status = HttpStatusCode.NotFound;
- }
- actionExecutedContext.Response = new HttpResponseMessage()
- {
- Content = new StringContent(message, System.Text.Encoding.UTF8, "text/plain"),
- StatusCode = status
- };
- base.OnException(actionExecutedContext);
- }
- }
接下來(lái)將自定義的異常過(guò)濾器添加到 HttpConfiguration 全局集合中,如下代碼所示:
- public static void Register(HttpConfiguration config)
- {
- config.MapHttpAttributeRoutes();
- config.Routes.MapHttpRoute(
- name: "DefaultApi",
- routeTemplate: "api/{controller}/{id}",
- defaults: new { id = RouteParameter.Optional }
- );
- config.Formatters.Remove(config.Formatters.XmlFormatter);
- config.Filters.Add(new CustomExceptionFilter());
- }
除了將自定義異常設(shè)置到全局上,你還可以縮小粒度到 Controller 或者 Action 級(jí)別上,下面的代碼分別展示了如何將其控制在 Action 和 Controller 上。
- [DatabaseExceptionFilter]
- public class EmployeesController : ApiController
- {
- //Some code
- }
- [CustomExceptionFilter]
- public IEnumerable<string> Get()
- {
- throw new DivideByZeroException();
- }
ASP.NET Web API 提供了強(qiáng)大的 HttpResponseException 來(lái)包裝異常信息,默認(rèn)情況下,當(dāng) WebAPI 中拋出異常,系統(tǒng)默認(rèn)使用 Http StateCode = 500 作為回應(yīng),也即:Internal Server Error. ,場(chǎng)景就來(lái)了,如果你會(huì)用 HttpResponseException 的話,就可以改變這種系統(tǒng)默認(rèn)行為,自定義錯(cuò)誤碼和錯(cuò)誤信息讓結(jié)果更加清晰語(yǔ)義化。
譯文鏈接:https://www.infoworld.com/article/2994111/how-to-handle-errors-in-aspnet-web-api.html