2017-10-07 66 views
-1

我覺得返回有意義的HTTP響應是個好主意,但我試圖想出正確的方法來處理這個問題。在ASP.NET Core 2.0 Web API中返回有意義的HTTP響應

在我的ASP.NET Core Web API應用程序中,端點(即API操作方法)僅接收請求,調用我的業務層以獲取響應並返回響應。

在業務層,我檢查請求是否被授權。如果它沒有被授權,我會拋出一個例外,它包含了未授權的請求類型,但在這些情況下,我的API端點只返回HTTP 500。我寧願退還HTTP 401

問題是如何將我的較低級別例外轉換爲HTTP狀態代碼。

兩個問題:

  1. 是否值得試圖捕捉例外發生在應用中的較低水平的類型,並嘗試將其翻譯爲HTTP反應,或者我應該只是讓我的API返回HTTP 500
  2. 如果值得,我該如何處理?
+0

因此,在5xx與4xx之間進行討論與錯誤消息的迴應是錯誤的。 –

+0

@Sam - 我同意阿列克謝,這個問題在這裏脫離主題。然而,如果你重新提出問題來問「怎麼做」而不是「我應該」這樣做,這將是一個合理的問題。 – NightOwl888

回答

1

假設您的控制器擴展了Microsoft.AspNet.MVC.Controller,您將繼承一些方法來執行您需要的操作,例如OK,Forbidden,BadRequest,ObjectResult等。因此,在上述情況下你可以不喜歡

public async IActionResult DoMyThing() 
{ 
    try 
    { 
     return ObjectResult(await DoMyInternalCall()); 
    } 
    catch (Exception e) 
    { 
     //FigureOut the Exception type indications a security violation 
     return Forbidden() 
    } 
    .... 

我個人傾向於建立一個返回狀態,而不是拋出一個異常,這使得這一切有點清潔尤其是現在,我們有元組的API。所以像

public async IActionResult DoMyThing() 
{ 
     var (Status status, string myThing) = await DoMyInternalCall(); 
     switch(status) 
     { 
      case Status.OK: return ObjectResult(myThing); 
          break; 

      case Status.AccessDenied: return Forbidden(); 
             break; 

      case Status.NotFound: return Notfound(); 

      ... 

雖然這只是一種滋味 - 我不判斷。關鍵是,Microsoft.AspNet.MVC.Controller內置了方法,可以讓您返回有效的HTTP狀態代碼和數據。

+0

這就是我一直在尋找的東西。謝謝! – Sam

0

當然有很多HTTP響應代碼,只是因爲請求無法正確處理並不一定意味着它是500內部服務器錯誤。如果有人要求更新一個不存在的對象會怎麼樣?這不會落在500的範圍之內(不確定哪一個可以正常工作 - 我猜可能是4xx,但推薦使用這個常用的HTTP響應列表)。我通常認爲,500人是爲了「呃,發生在我們身上的事情,我們不知道...」類型的事情。對於大多數其他情況,還有更合適的迴應。

就這樣說,我覺得例外是最好的概括,因爲他們進一步走向頂層。實體框架引發了一些深奧的異常,數據訪問層將其包裝在一個稍微更通用的DataAccessException中(當然,原始內部爲原始),存儲庫可能更加通用地處理它,並且在它到達控制器時對於響應處理,您應該只有少數應該需要處理的「實際」異常。返回相當通用的東西,在服務器上記錄嵌套的異常,並從那裏去?

我的2分錢小費

0

一個Web API應該努力永遠不會返回500狀態代碼(內部服務器錯誤)。如果確實如此,那麼你寫的代碼有問題。

話雖如此,你不應該拋出一個異常,意圖發回一個狀態代碼是一個相當差的方式來處理請求 - 即通過做一個毯子捕獲所有和掩蓋它與一些不錯的狀態代碼給客戶。

您應該對請求運行所有驗證和邏輯,並將您選擇的任何4xx狀態代碼發回。

從本質上講,一個Web API的狀態碼應該是

2XX -- Success //(ex: OK, created, no content, etc) 
3XX -- Redirection //(ex: renamed an API's path/url to a new one) 
4XX -- Client Error 
     ex: 
      405 //Method Not Allowed (ex: client sent a DELETE request to your API) 
      409 //Conflict 
      415 //Unsupported Media Type (ex: client requests for XML -- yuck! no!) 
      416 //Range Not Suitable (ex: client asked for a million records) 
      422 //Unpronounceable Entity (ex: client sent something invalid in the body) 
5XX -- Server Error //(ex: a well written Web API will NEVER error!) 

但是,如果你真的有一個例外,那麼500錯誤代碼是正確的 - 這意味着你寫不好的代碼(請參考我的第一點)。

+0

您是否在說我應該檢查用戶是否在API級授權,而不是在業務層? – Sam

+0

@Sam我不能確定根據提供的信息,但實際上你應該試圖在每一層進行驗證。永遠不要假設層之間的數據是有效的。 – Svek

+0

@Sam通常越早,您可以阻止**請求**,使其沿請求管道向下傳遞(每層進一步傳遞)越好。這意味着大多數例外不太可能首先發生。 – Svek

0

我不喜歡這種拋出異常的想法。 500是一個標誌,說明你自己的代碼有一些錯誤。

因此,假設您的業務層正在檢查用戶是否被授權。我會做的是創建一個方法來檢查授權,讓該方法返回一個簡單的布爾響應,例如。然後你的控制器檢查標誌,如果它是假的,返回401,完成工作。這是在業務層和api層之間進行通信的更好方式。

很明顯,我無法知道您的業務層是如何構建的,但保持簡單,保持清晰,不要試圖捕獲任何異常,乾淨地處理所有內容並返回適當的HTTP代碼。

業務層不應該關心api,不應該處理HTTP代碼,基本上這意味着您不會在任何地方泄漏抽象,並且將事物保留在它們所屬的層中。

相關問題