下面由laravel教程欄目給大家介紹一種對于laravel異常作為返回的解決方式,希望對需要的朋友有所幫助!
-
我們假定一個場景,用戶注冊, 需要參數(shù)
參數(shù)名 解釋 類型 是否必填 mobile 用戶手機(jī)號碼 字符串 必填 sms_code 短信驗(yàn)證碼 整數(shù) 必填 password 用戶密碼 字符串 用戶密碼 re_password 重復(fù)用戶密碼 整數(shù) 重復(fù)用戶密碼 -
以下列舉會出現(xiàn)的問題情況
- 用戶短信不匹配
- 用戶短信類型錯誤
- 用戶密碼不相同
- 手機(jī)號已經(jīng)使用過 直接登錄即可
- 用戶密碼類型不符合要求
- 短信驗(yàn)證碼不能為空
- 手機(jī)號碼不能為空
- 兩個密碼都不能為空
-
現(xiàn)在已知會復(fù)用的場景有 ?會在別的業(yè)務(wù)內(nèi)有相同錯誤的類型 (具體業(yè)務(wù)不做贅述,業(yè)務(wù)不同,理解不同)
- 短信驗(yàn)證 checkSms 驗(yàn)證短信驗(yàn)證碼是否正確 類型是否匹配
- 修改密碼 ?提示密碼類型錯誤等場景
-
這里假定大家都不是大佬 業(yè)務(wù)有藕合 處理方案如下 (以下代碼僅在checkSms下進(jìn)行)
- 在checkSms函數(shù)里面直接
//第一次寫文檔 不會用markdown 你也可以用 response出去 這樣淺顯易懂exit(json_encode(['code'=>-1,'msg'=>'短信驗(yàn)證碼錯誤']));
- 每處都做判斷
if (false === checkSms($mobile,$code,$type)){ exit(json_encode(['code'=>-1,'msg'=>'短信驗(yàn)證碼錯誤']));}
- 看看我的方式 (這句要怎么加粗啊)
- 在checkSms函數(shù)里面直接
-
已知你有三套業(yè)務(wù) 且每套業(yè)務(wù)包含N個子模塊 (別杠微服務(wù)/跨語言等,杠就是你贏 /狗頭)
- 現(xiàn)在出了問題 前端告訴你 code=-1 message=>’系統(tǒng)錯誤 || 需要登錄 || 商品查詢失敗 || 短信失敗 等各種錯誤信息 ‘
你什么心情????????????? 開始到處找,這個message在哪, 誰寫的 ,什么時候?qū)懙?到底是哪個等 - 業(yè)務(wù)有藕合, 你在你的業(yè)務(wù)里面用的某一個service(僅做偽例子)內(nèi)的action 發(fā)現(xiàn)拋出了一個你不清楚的異常,你去問,貼日志
結(jié)果必然是 ?你找的人去執(zhí)行我上面說的那條,依次遞歸. 直到Fatal error: Allowed memory size of 1073741824 bytes exhausted (tried to allocate 9216 bytes) in your problem
我就找不到在哪,我就是懵 日常維護(hù)老項(xiàng)目的同學(xué)豈不是人都沒了… 為什么大家都是接盤,我缺過得這么難
- 現(xiàn)在出了問題 前端告訴你 code=-1 message=>’系統(tǒng)錯誤 || 需要登錄 || 商品查詢失敗 || 短信失敗 等各種錯誤信息 ‘
-
與其到處去找不如直接告訴我是怎么回事,但是你又很難保證大家寫的錯誤信息內(nèi)容都是一樣的
-
首先我們明白一個道理 你寫代碼最害怕的是什么 是bug嗎? 不是
是這個
你問我錯哪了? ?我怎么知道!!!!! 我就知道肯定報錯了 拋出異常了 ,程序停了啊!!! -
ok 那么我們知道了一個道理,當(dāng)程序拋出異常的時候,項(xiàng)目就會停掉.
?同時我們也明白了一件事 叫做: -
假定我們有一個業(yè)務(wù)模塊叫做 User 里面包含了一個控制器叫做 AuthController
內(nèi)部需要完成一個login的行為<?php namespace AppHttpControllersApplicationAuth; use AppHttpControllersController; use AppHttpRequestsApplicationAuthLoginRequest; use IlluminateHttpJsonResponse; class AuthController extends Controller { // public function index(LoginRequest $loginRequest): JsonResponse { $data = $loginRequest->all(); //todo 驗(yàn)證是否登錄成功 //todo 登錄成功之后需要從返回里面獲取token 和 userInfo //todo 記錄日志等行為 //todo 返回前端 return $this->success('登陸成功', compact('token', 'user')); } }
- 一般會怎么做
-
if (!empty(login($username,$password))){ //todo 登錄成功 //tonext}
-
- 一旦出錯 怎么辦?????? 開始
if(1){ if(1){ if(1){ if(1){ //建議這里直接用來測光速到底是多少 ,因?yàn)樾枨笫菬o限長的 //并且你知道到底是什么問題,什么業(yè)務(wù)返回來的,到底的意思是什么嘛? (突然成為派大星 ) } } } }
- 如果你覺得 上面這個方案或者類似這個方案很棒,那我收回剛才那張圖
- 一般會怎么做
-
-
我們上面已知程序拋出異常就會停掉,除非你繼續(xù)catch 然后拋什么出來??????怕不是萬能交稅
? 1.我們設(shè)計讓我們的程序聽話,怎么聽話,讓他犯錯自己會停,還會告訴你怎么回事
? 2.怎么實(shí)現(xiàn),這么做的意義是什么
? 3.如何實(shí)現(xiàn),這樣做有什么別的意義沒
? 4.性能損耗問題 -
回答問題
?1.你是開發(fā),程序是你的 你必須說什么讓他聽什么
?2.此處僅做流程展示,最后會直接貼代碼加注釋,如果沒耐心可以直接翻最后 創(chuàng)建異常應(yīng)該都o(jì)k吧,不ok 就去看文檔 你可以停在這了<?php namespace AppExceptions; use Exception; class XxxException extends Exception { /** * @Message('短信驗(yàn)證碼錯誤') */ const SMS_CODE_IS_ERROR = '300000000'; /** * @Message('短信驗(yàn)證碼類型錯誤') */ const SMS_CODE_TYPE_IS_ERROR = '300000001'; /** * @Message('短信驗(yàn)證碼不存在') */ const SMS_CODE_IS_NOT_EXISTS = '300000002'; } ?>
-
偽代碼
//todo 驗(yàn)證碼類型錯誤throw new XxxException(XxxException::SMS_CODE_IS_ERROR);
程序現(xiàn)在是不是應(yīng)該停下來了,因?yàn)楫?dāng)你exception的時候 下面代碼不會執(zhí)行了
但是新的問題出現(xiàn)了,如果這樣拋出異常,前端怎么辦???????????
此處小聲bb 前端處理不了跟我什么關(guān)系啊,我是后臺啊,你有問題找前端啊.
那么我們假設(shè)一下 如果我們告訴前端的是{code:'300000000','message:'短信驗(yàn)證碼錯誤'}
是不是就很舒服了,前后端是一家 怎么能鬧脾氣呢
那么如果 Code統(tǒng)一,請問出問題你在發(fā)愁什么? 是你的phpstorm不存在屬性追蹤嗎? -
怎么實(shí)現(xiàn)???????????????
?你問我,我也不到啊 ?我只能給你這個啊<?php namespace AppExceptions;use AppFactoryParseException; //解釋異常的工廠 嫌棄名字長就沒加Factory use AppTraitsResponseTrait; //這個是我自己寫的一個簡單的trait 也會一并貼上去use IlluminateDatabaseEloquentModelNotFoundException;use IlluminateFoundationExceptionsHandler as ExceptionHandler;use IlluminateHttpJsonResponse;use IlluminateHttpResponse;use IlluminateSupportStr;use IlluminateValidationValidationException;use SymfonyComponentHttpKernelExceptionMethodNotAllowedHttpException;use SymfonyComponentHttpKernelExceptionNotFoundHttpException;use Throwable;class Handler extends ExceptionHandler{ use ResponseTrait; /** * A list of the exception types that are not reported. * * @var array */ protected $dontReport = [ // ]; /** * A list of the inputs that are never flashed for validation exceptions. * * @var array */ protected $dontFlash = [ 'current_password', 'password', 'password_confirmation', ]; /** * Register the exception handling callbacks for the application. * * @return void */ public function register() { $this->reportable(function (Throwable $e) { // }); } public function render($request, $e) { //數(shù)據(jù)庫沒查到數(shù)據(jù)或者數(shù)據(jù)是softdelete if ($e instanceof ModelNotFoundException) { return $this->error('500', '數(shù)據(jù)不存在或已刪除'); } //非允許請求方式 if ($e instanceof MethodNotAllowedHttpException) { return $this->error('422', '請求方式錯誤'); } //驗(yàn)證失敗 if ($e instanceof ValidationException) { return $this->error(412, current(current($e->errors()))); } //這里是為了兼容其他的一些錯誤 if (Str::length($e->getMessage()) > 1 && Str::length($e->getCode()) > 1) { return $this->error($e->getCode(), $e->getMessage()); } //處理我們自己的錯誤 $result = ParseException::parseException($e); //這里判斷的原因很簡單 因?yàn)榭赡苓@個code沒有按照規(guī)范聲明 if (is_array($result)) { return $this->error($result['code'], $result['message']); } // Object Not Found 你懂我意思吧? if ($e instanceof NotFoundHttpException) { return $this->error('404', '頁面路徑不存在'); } //這里可以根據(jù)自己是否需要做兜底而決定是否兜底 }}
parseException
<?php namespace AppFactory;use IlluminateSupportFacadesLog;class ParseException{ public static function parseException(Throwable $exception) { //注解 不懂得話建議直接看文檔->反射 ,我講不明白這個東西 $annotation = new ReflectionClass($exception); //翻轉(zhuǎn) 成code->constant $values = array_flip($annotation->getConstants()); if (empty($values)) { return false; } //拿到對應(yīng)的constant $constant = $values[$exception->getMessage()]; //constant反射 $annotation_text = new ReflectionClassConstant($exception, $constant); //獲取屬性注釋內(nèi)容 $comment = $annotation_text->getDocComment(); try { //正則大法好 建議留意此處 preg_match("/Message('(.*?)')(rn|r|n)/U", $comment, $result); } catch (Throwable $e) { return false; } if (false === isset($result[1])) { return false; } return [ 'code' => $exception->getMessage(), 'message' => $result[1] ]; }}
不要問我要 ResponseTrait ?我相信一個簡單的 響應(yīng)實(shí)現(xiàn)你是ok的
這樣實(shí)現(xiàn)的意義就是為了不管誰接手項(xiàng)目前端后端 看到錯誤信息一目了然,就算某天領(lǐng)導(dǎo)說不要需要告訴用戶短信什么錯了,就告訴他你短信錯了,你只需要去改constant而已!
并且可讀性高,ide支持 ,如果你覺得不合適,那我沒轍了 ,我盡力了 -
性能損耗
?目前沒發(fā)現(xiàn)很明顯的性能損耗,給出的調(diào)優(yōu)方案也是 如果可以的話注解的類的屬性列表(讓你留意的地方)可以做緩存而已 ,(因?yàn)槲夷壳安恍枰タ紤]這個,laravels大法好)
-
-
不出意外的話我的代碼你拿著直接貼進(jìn)去就可以用,但是我不建議你這么做,因?yàn)橐淮纬燥柌淮砟芤恢背燥?我希望你能清楚起碼也要點(diǎn)贊,不能白嫖這個道理
我第一次寫markdown ?如果有什么寫的不好的,可以及時留言我看到會盡力去改,如果有明顯的代碼錯誤,請?zhí)崾疚?我好把你的留言刪除掉 .
不要企圖假裝努力,因?yàn)榻Y(jié)果不會陪你一起假裝~! (這個字的顏色怎么改?)