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