Laravel異常上下文解決方案分享
前言
異常時我們通常希望在用戶側(cè)給一個友好的提示,但默認(rèn)使用框架的異常處理方案是不 OK 的。
最近項目遇到一個情況,我們在遇到用戶訪問某個信息沒有權(quán)限的時候,希望提示詳細(xì)的原因,比如當(dāng)訪問一個團(tuán)隊資源時非成員訪問的場景下會提示一個:您不是 [xxxxxx] 團(tuán)隊的成員,暫時無法查看,可<申請加入>,同時需要顯示打碼后的團(tuán)隊名稱,以及加入按鈕,可是接口方的邏輯是當(dāng)沒有權(quán)限時直接 abort 了:
abort_if(!$user->isMember($resouce->team), 403, '您無權(quán)訪問該資源');
得到的響應(yīng)結(jié)果如下:
HTTP/1.0 403 Forbidden
{
"message": "您無權(quán)訪問該資源"
}
我們不可能將 message 用 html 來完成前端提示頁的展示,這樣耦合性太強(qiáng),違背了前后端分離的原則。我們的目標(biāo)是返回如下的格式即可解決:
HTTP/1.0 403 Forbidden
{
"message": "您無權(quán)訪問該資源",
"team": {
"id": "abxT8sioa0Ms",
"name": "CoDesign****"
}
}
通過攜帶上下文的方法傳遞數(shù)據(jù),方便了前端同學(xué)自由組合。
開始改造
當(dāng)然這并不是什么復(fù)雜的事情,直接修改原來的 abort_if 即可解決:
- abort_if(!$user->isMember($resouce->team), 403, '您無權(quán)訪問該資源');
+ if (!$user->isMember($resouce->team)) {
+ return response()->json([
+ 'message' => '您無權(quán)訪問該資源',
+ 'team' => [
+ 'id' => $resouce->team_id,
+ 'name'=> $resouce->team->desensitised_name,
+ ]
+ ], 403);
+ }
這樣看起來解決了問題,可是試想一下,如果是在閉包里面檢測到異常想要退出,上面這種 return 式的寫法就會比較難搞了,畢竟 return 只會終止最近的上下文環(huán)境,我們還是希望像 abort 一樣能終止整個應(yīng)用的執(zhí)行,再進(jìn)行另一番改造。
優(yōu)化實現(xiàn)
看了 abort 源碼,我發(fā)現(xiàn)它的第一個參數(shù)其實支持 \Symfony\Component\HttpFoundation\Response 實例,而上面??我們 return 的結(jié)果就是它的實例,所以我們只需要改成這樣就可以了:
if (!$user->isMember($resouce->team)) {
abort(response()->json([
'message' => '您無權(quán)訪問該資源',
'team' => [
'id' => $resouce->team_id,
'name'=> $resouce->team->desensitised_name,
]
], 403));
}
新的問題來了,如果需要復(fù)用的時候還是比較尷尬,這段代碼將會重復(fù)出現(xiàn)在各種有此權(quán)限判斷的地方,這并不是我們想要的。
邏輯復(fù)用
為了達(dá)到邏輯復(fù)用,我認(rèn)證看了 \App\Exceptions\Handler 的實現(xiàn),發(fā)現(xiàn)父類的 render 方法還有這么一個設(shè)計:
public function render($request, Throwable $e)
{
if (method_exists($e, 'render') && $response = $e->render($request)) {
return Router::toResponse($request, $response);
} elseif ($e instanceof Responsable) {
return $e->toResponse($request);
}
//...
所以,我們可以將這個邏輯抽離為一個獨立的異常類,實現(xiàn) render 方法即可:
$ ./artisan make:exception NotTeamMemberException
代碼如下:
<?php
namespace App\Exceptions;
use App\Team;
class NotTeamMemberException extends \Exception
{
public Team $team;
public function __construct(Team $team, $message = "")
{
$this->team = $team;
parent::__construct($message, 403);
}
public function render()
{
return response()->json(
[
'message' => !empty($this->message) ? $this->message : '您無權(quán)訪問該資源',
'team' => [
'id' => $this->team->id,
'name' => $this->team->desensitised_name,
],
],
403
);
}
}
這樣一來,我們的邏輯就變成了:
if (!$user->isMember($resouce->team)) {
throw new NotTeamMemberException($resouce->team, '您無權(quán)訪問該資源');
}
當(dāng)然也可以簡化為:
\throw_if(!$user->isMember($resouce->team), NotTeamMemberException::class, $resouce->team, '您無權(quán)訪問該資源');
問題到這里總算以一個比較完美的方式解決了,如果你有更好的方案歡迎評論探討。
總結(jié)
到此這篇關(guān)于Laravel異常上下文解決方案的文章就介紹到這了,更多相關(guān)Laravel異常上下文解決內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
PhpStorm 如何優(yōu)雅的調(diào)試Hyperf的方法步驟
這篇文章主要介紹了PhpStorm 如何優(yōu)雅的調(diào)試Hyperf的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11
PHP中為什么使用file_get_contents("php://input")接收微信通知
微信用戶和公眾號產(chǎn)生交互的過程中,用戶的某些操作會使得微信服務(wù)器事件推送,通知到開發(fā)者中心設(shè)置的服務(wù)器地址(回調(diào)url),開發(fā)者可以獲取到該信息。PHP中為什么使用file_get_contents("php://input")來接收呢?為什么有些場景php://input接收不到?2023-07-07
php版微信開發(fā)之接收消息,自動判斷及回復(fù)相應(yīng)消息的方法
這篇文章主要介紹了php版微信開發(fā)之接收消息,自動判斷及回復(fù)相應(yīng)消息的方法,涉及基于微信消息處理接口的調(diào)用相關(guān)操作技巧,需要的朋友可以參考下2016-09-09
ajax在joomla中的原生態(tài)應(yīng)用代碼
一般很少看到j(luò)oomla中使用ajax,筆者以前說到過用jquery來實現(xiàn),對于那些驗證用戶名不能重復(fù),郵箱不能重復(fù),以及聯(lián)動菜單,等等的應(yīng)用,使用ajax是免不了的2012-07-07

