微服務的設計原則
阿新 • • 發佈:2019-02-19
呼叫鏈中的異常處理
假設微服務serviceA的介面interfaceA被微服務serviceB呼叫,如果interfaceA在呼叫過程中會丟擲異常,那麼是否該將該異常以狀態碼傳給serviceB呢?
對於RPC來說(如Feign),會自動將被呼叫的遠端介面的異常在呼叫方以異常丟擲;對於Rest Api來說,可以將異常包裝到response的out中。
我建議serviceB在呼叫interfaceA時,判斷interfaceA是否出現異常應該儘量不要依賴於判斷interfaceA返回的狀態碼。因為讀取狀態碼是要獲取response物件,而這樣會造成程式碼不必要的拖沓。
儘量不要這麼寫:
@GetMapping(path = "/interfaceA")
public String methodA(@RequestParam String input)throw SomeException{
...
return res;
}
應該這麼寫:
@GetMapping(path = "/interfaceA")
public String methodA(@RequestParam String input){
try{
...
}catch(SomeException e){
logger.error("error reason" , e);
return "error reason";
}
return res;
}
這樣,出現異常時候,可以在serviceA記錄異常原因,同時將異常原因返回給serviceB,這樣serviceB可以通過返回字串來判斷是否執行成功。
而對於返回物件的介面,則可以在出現異常時通過返回null來告訴serviceB調用出現異常。
另外:
- 介面能返回String儘量不要返回Boolean,應該讓serviceB儘可能知悉異常原因。(返回物件就沒辦法了)
- 如果interfaceA只有前端呼叫,interfaceA丟擲異常返回狀態碼也是可以的(不過誰能保證interfaceA以後不被其他微服務呼叫呢?)
介面路徑定義原則
介面路徑
應該儘量將傳遞的變數input
放在RequestParam
:
@GetMapping(path = "/interfaceA")
public String methodA(@RequestParam String input){
...
return res;
}
即使要放在path也應該這樣:
@GetMapping(path = "/interfaceA/{input}")
public String methodA(@PathVariable("input") String input){
...
return res;
}
而不應該這樣放在path:
@GetMapping(path = "/{input}/interfaceA")
我們應該儘可能保證可以通過某種方式形成路徑命名子空間,從而隔離開各個介面,方便dispatcher分派request。第三種方式容易造成路徑命名子空間汙染。