摘要:關于拋出異常如在我的上一篇文中所說的一樣在接口的設計中接口的返回的數據是非常重要的例如無法避免的等等這些都是要命的錯誤同時還有一個極大的問題就是在新增模塊中例如我最近需要新增一個的分詞查詢模塊這個在添加索引刪除索引等等操作的時候是非常容易導
關于拋出異常
如在我的上一篇文中所說的一樣, 在接口的設計中, 接口的返回的數據是非常重要的, 例如無法避免的500等等, 這些都是要命的錯誤
同時還有一個極大的問題, 就是在新增模塊中, 例如我最近需要新增一個 elasticsearh 的分詞查詢模塊, 這個在添加索引刪除索引等等操作的時候, 是非常容易導致拋出錯誤異常的.
按照平常的解決思路, 我們可能首先就是針對異常處理直接進行使用Exception進行捕獲,/偷笑, 我在以前的時候也是非常喜歡這么做的
1) try catch (1)
代碼案例:
public function addIndex($data) { $params = [ "index" => "show", "type" => "store", "body" => $data ]; try{ $this->client->index($params); }catch (Exception $exception) { halt("參數錯誤的異常"); # 處理錯誤1 } }
在我們初期的學習和開發當前,以上的方法的確是可行的,類似于我們常常說的 JQ一把梭 , 上面的便是 錯誤一刀切,這種方式的確是能夠進行解決問題, 但是非常不利于針對某個錯誤的處理
例如 BadRequest400Exception 方法拋出的 getMessage() 的結果是json數據, 而 BadMethodCallException 拋出的是字符串數據 你告訴我怎么處理呢?
所以, 衍生了如下的第二種處理錯誤方式
2) try catch (2)
代碼案例:
public function addIndex($data) { $params = [ "index" => "show", "type" => "store", "body" => $data ]; try{ $this->client->index($params); }catch (BadRequest400Exception $e) { $msg = json_decode($e->getMessage(), true); halt("參數錯誤的異常:" . $msg); # 處理錯誤1 }catch (BadMethodCallException $e){ halt("方法不存在的錯誤異常:" . $e->getMessage()); # 處理錯誤2 }catch(Exception $e) { halt("系統異常"); } }
恩, 的確,以上也算是我們平常常見的一種解決方式, 但是, 有沒有考慮過代碼冗余呢, 如果10個需要捕獲錯誤的方法, 難道就寫10個嗎 . 這個時候,我們需要一個 耦合掉這些方法的操作 , 盡管php7中錯誤異常的支持越來越強大, 但面對業務場景的不斷增加,我們必須采取 可靠 穩定 了解 的三種標準來要求它. 了解的意思是, 能夠給我們輸出清楚的錯誤日志等
步入正題開發框架是thinkphp5.1
異常處理接管
thinkphp給我們提供了強大的異常處理機制, 當然市場上的框架基本都能提供這個功能. 我們找到文檔錯誤處理的那一塊, (https://www.kancloud.cn/manua...[https://www.kancloud.cn/manual/thinkphp5_1/354092#_42]
基于tp自帶的, 再其基礎上進行優化更加豐富的自定義異常處理, 這便是我所理解的異常處理接管吧
進行業務設計定義個異常處理接管, 重寫render方法 , 這個方法主要是拋出一個響應異常 .
注意注意 ~~!!
查看源碼還有我的經驗得知, 它必須是 return 的方式 , 返回一個 Response 創建的響應異常, 否則會給你拋出莫名其妙的錯誤
閱讀如下文章, 請先查看 http://surest.cn/archives/71/這個文章
主要是了解一下 https://github.com/surest-sky/example/blob/master/laravel%E7%9A%84%E4%B8%80%E4%BA%9B%E5%86%99%E6%B3%95/ApiResponse_tp.php的用法
異常處理接管的代碼如下
isAjax() || $isDebug) { // return parent::render($e); // } # 錯誤的信息, 用于寫入日志 $error_info = [ "code" => $e->getCode(), # 錯誤代碼描述 "line" => $e->getLine(), # 錯誤代碼行 "message" => $e->getMessage(), # 錯誤詳細信息 "file" => $e->getFile() # 錯誤文件名稱 ]; # 捕獲錯誤處理異常 return $this->handler_exception($e, $error_info); }catch (Exception $exception) { return parent::render($exception); } } /** * 加載錯誤處理 * @param $e */ public function handler_exception($e, $error_info) { foreach ($this->handler_exceptions as $exception) { $exception = new $exception; if($exception->handler($e, $error_info) instanceof Response){ return $exception->handler($e, $error_info); } } } }
它的流程大概是
handler_exceptions: 定義需要捕獲異常的錯誤處理模塊
render : 重寫錯誤處理異常
error_info 用來分發給各個子模塊異常, 用來需要的地方進行打印日志
catch (Exception $exception) : 這個的用處不大, 主要是這個如果出現錯誤的話,自己處理不了, 就交給tp自帶的異常處理去處理 return parent::render($exception); 執行父方法
handler_exception
這個就是, 來遍歷執行是否需要捕獲的錯誤的模塊, 依次加載, 當真實的響應了錯誤的時候(會繼承Response方法), 就表明的確是發生錯誤了, 具體看下面
功能模塊的異常處理這里查看 elasticSearch 的方法
showMsg($e->getMessage(), $error_info); break; case "ElasticsearchCommonExceptionsBadRequest400Exception" : return $this->showMsg(json_decode($e->getMessage(), true), $error_info); break; } # 否則不返回錯誤異常 } }
流程解釋, 如上可以看到, 我們繼承了 BaseException 并且實現了 CustomExceptionInterface 接口
BaseException
namespace appcommonexception;
use appcommonTraitsApiResponse;
class BaseException
{
use ApiResponse; public function __construct() { # 這個必須強制設置為true $this->is_anomaly_andling_takeover = true; # 檢查當前異常處理是否繼承了異常處理接管, 沒有則拋出一個異常 if(!($this instanceof CustomExceptionInterface)) { return $this->showMsg(__CLASS__ . "必須繼承CustomExceptionInterface這個接口", []); } } public function showMsg($msg, array $error_info, $code = 500) { return $this->status($msg, compact("error_info"), $code, $code); }
}
CustomExceptionInterface
/**
Created by PhpStorm.
User: 鄧塵鋒
Date: 19-5-13
Time: 上午9:35
*/ namespace appcommonexception; /** * 定義一個異常處理接口, 只要是appcommonexception下的子類, 必須繼承它 * Interface CustomExceptionInterface * @package appcommonexception */ Interface CustomExceptionInterface { public function handler($e, array $error_info); # 接受異常處理 public function showMsg($msg, array $error_info, $code); # 拋出錯誤消息 }
流程解釋 :
BaseException 使用了 ApiResponse 用于拋出異常,
定義的 showMsg 是為了實現 CustomExceptionInterface 接口, 作用在于返回一個 response 的錯誤
$this->is_anomaly_andling_takeover 這個是為了重寫定義 ApiResponse 的響應, 在原先的 ApiResponse 中
public function respond($data, $header = []) { $type = request()->isAjax() ? "json" : "html"; $response = JsonResponse::create($data, $type, $this->code, $header); throw new HttpResponseException($response); }
他是直接拋出的 HttpResponseException 異常的錯誤, 顯然不符合我們之前所說的 它必須是 return 的方式 , 返回一個 Response 創建的響應異常, 否則會給你拋出莫名其妙的錯誤, 所以重新定義屬性
public function respond($data, $header = []) { $type = request()->isAjax() ? "json" : "html"; $response = JsonResponse::create($data, $type, $this->code, $header); if( $this->is_anomaly_andling_takeover ) { return $response; # 拋出 response 異常 } throw new HttpResponseException($response); }
這樣 showMsg 方法就返回的是 response 異常了
在子類 handler 方法中, 就可以輕松的定義你的錯誤異常咯
public function handler($e, array $error_info) { $e_class = get_class($e); switch ($e_class) { case "ElasticsearchCommonExceptionsUnexpectedValueException": return $this->showMsg($e->getMessage(), $error_info); break; case "ElasticsearchCommonExceptionsBadRequest400Exception" : return $this->showMsg(json_decode($e->getMessage(), true), $error_info); break; } # 否則不返回錯誤異常 }
如之前所說的, 我們可以把添加所以那一串代碼演化成
public function addIndex($data) { $params = [ "index" => "show", "type" => "store", "body" => $data ]; $this->client->index($params); }
再也不需要進行捕獲了, 如果它拋出錯誤了, 會自動走到 handler 中, 并且響應一個你定義的異常
再添加一個錯誤處理眾所周知, 他是路由出現的異常問題是不可避免的, 我們來這樣定義
在 appcommonexceptionHandler 屬性 handler_exceptions 中添加 "appcommonexceptionRouteExceptionHandler", 并且定義他
... use thinkexceptionHttpException; class RouteExceptionHandler extends BaseException implements CustomExceptionInterface { public function handler($e, array $err_info) { # 檢測理由錯誤 if( $e instanceof HttpException) { return $this->showMsg("當前請求路由不存在", $err_info, 404); } }
即可
響應結果:
{ "msg": "當前請求路由不存在", "code": 404, "error_info": { "code": 0, "line": 63, "message": "module not exists:store", "file": "/www/wwwroot/app/thinkphp/library/think/route/dispatch/Module.php" } }完結
代碼實例在
https://github.com/surest-sky/example/tree/master/exception
來源鄧塵鋒
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/31444.html
摘要:畢竟永遠相信本文能給你帶來意想不到的收獲使用示例關于數據校驗這一塊在中的使用案例,我相信但凡有點經驗的程序員應該沒有不會使用的,并且還不乏熟練的選手。 每篇一句 NBA里有兩大笑話:一是科比沒天賦,二是詹姆斯沒技術 相關閱讀 【小家Java】深入了解數據校驗:Java Bean Validation 2.0(JSR303、JSR349、JSR380)Hibernate-Validati...
摘要:異常處理的個最佳實踐原文地址翻譯出處在中,異常處理是個很麻煩的事情。使用描述性消息拋出異常這個最佳實踐背后的想法與前兩個類似。當你以錯誤的格式提供時,它將被類的構造函數拋出。類提供了特殊的構造函數方法,它接受一個作為參數。 Java 異常處理的 9 個最佳實踐 原文地址:https://dzone.com/articles/9-...翻譯出處:https://www.oschina.n...
摘要:所以是在一秒后顯示的。這個行為不會耗費資源,因為引擎可以同時處理其他任務執行其他腳本,處理事件等。每個回調首先被放入微任務隊列然后在當前代碼執行完成后被執行。,函數是異步的,但是會立即運行。否則,就返回結果,并賦值。 「async/await」是 promises 的另一種更便捷更流行的寫法,同時它也更易于理解和使用。 Async functions 讓我們以 async 這個關鍵字開...
摘要:在使用手動拋出異常時,希望跳轉到自定義的錯誤頁面,官方的文章中是這樣描述的。只能看源碼找問題了。而這個布局文件的路徑是一個相對路徑,這時如果你拋出異常的地方不是在的里,就找不到布局文件了。在使用HttpException手動拋出異常時,希望跳轉到自定義的錯誤頁面,官方的文章中是這樣描述的。 可以使用thinkexceptionHttpException類來拋出異常 // 拋出 HTTP 異...
摘要:當觸發異常的字節碼的索引值在某個異常表條目的監控范圍內,虛擬機會判斷所拋出的異常和該條目想要捕獲的異常是否匹配。 作者:李瑞杰目前就職于阿里巴巴,狂熱JVM愛好者讓我們準備一個函數:showImg(https://user-gold-cdn.xitu.io/2019/5/19/16acbce35adfefb7);然后,反編譯他的字節碼:showImg(https://user-gold-cd...
閱讀 537·2023-04-25 14:26
閱讀 1292·2021-11-25 09:43
閱讀 3485·2021-09-22 15:25
閱讀 1454·2019-08-30 15:54
閱讀 528·2019-08-30 12:57
閱讀 773·2019-08-29 17:24
閱讀 3170·2019-08-28 18:13
閱讀 2691·2019-08-28 17:52