首頁 > php框架 > Laravel > 分享一個Laravel異常上下文解決方案

分享一個Laravel異常上下文解決方案

藏色散人
發布: 2021-01-22 09:05:13
轉載
1970 人瀏覽過

下上由Laravel教學#專欄為大家一起介紹一種Laravel異常情境解決方案,希望對需要的朋友有所幫助!

最近專案遇到一個狀況,我們在遇到使用者存取某個資訊沒有權限的時候,希望提示詳細的原因,例如當存取一個團隊資源時非成員存取的場景下會提示一個: 您不是[xxxxxx] 團隊的成員,暫時無法查看,可<申請加入>,同時需要顯示打碼後的團隊名稱,以及加入按鈕,可是接口方的邏輯是當沒有權限時直接abort 了:

abort_if(!$user->isMember($resouce->team), 403, '您无权访问该资源');
登入後複製

得到的回應結果如下:

HTTP/1.0 403 Forbidden{
    "message": "您无权访问该资源"}
登入後複製

我們不可能將message 用html 來完成前端提示頁的展示,這樣耦合性太強,違背了前後端分離的原則。我們的目標是返回如下的格式即可解決:

HTTP/1.0 403 Forbidden{
    "message": "您无权访问该资源",
    "team": {
        "id": "abxT8sioa0Ms",
        "name": "CoDesign****"
    }}
登入後複製

透過攜帶上下文的方法傳遞數據,方便了前端同學自由組合。

開始改造

當然這並不是什麼複雜的事情,直接修改原來的abort_if# 即可解決:

- abort_if(!$user->isMember($resouce->team), 403, &#39;您无权访问该资源&#39;);
+ if (!$user->isMember($resouce->team)) {
+    return response()->json([
+        &#39;message&#39; => &#39;您无权访问该资源&#39;,
+        &#39;team&#39; => [
+            &#39;id&#39; => $resouce->team_id,
+            &#39;name&#39;=> $resouce->team->desensitised_name,
+        ]
+    ], 403);
+ }
登入後複製

這樣看起來解決了問題,可是試想一下,如果是在閉包裡面檢測到異常想要退出,上面這種return 式的寫法就會比較難搞了,畢竟return 只會終止最近的上下文環境,我們還是希望像abort 一樣能終止整個應用的執行,再進行另一番改造。

優化實作

看了abort 原始碼,我發現它的第一個參數其實支援 \Symfony\Component\HttpFoundation\Response 實例,而上面我們return 的結果就是它的實例,所以我們只需要改成這樣就可以了:

 if (!$user->isMember($resouce->team)) {
    abort(response()->json([
        &#39;message&#39; => &#39;您无权访问该资源&#39;,
        &#39;team&#39; => [
            &#39;id&#39; => $resouce->team_id,
            &#39;name&#39;=> $resouce->team->desensitised_name,
        ]
    ], 403));
 }
登入後複製

看起來實現了異常中斷,可是新的問題來了,如果需要復用的時候還是比較尷尬,這段程式碼將會重複出現在各種有此權限判斷的地方,這並不是我們想要的。

邏輯復用

為了達到邏輯復用,看了\App\Exceptions\Handler 的實現,發現父類別的render 方法還有這麼一個設計:

public function render($request, Throwable $e)
{
    if (method_exists($e, &#39;render&#39;) && $response = $e->render($request)) {
        return Router::toResponse($request, $response);
    } elseif ($e instanceof Responsable) {
        return $e->toResponse($request);
    }
    //...
登入後複製

所以,我們可以將這個邏輯抽離為一個獨立的異常類,實現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(
            [
                &#39;message&#39; => !empty($this->message) ? $this->message : &#39;您无权访问该资源&#39;,
                &#39;team&#39; => [
                    &#39;id&#39; => $this->team->id,
                    &#39;name&#39; => $this->team->desensitised_name,
                ],
            ],
            403
        );
    }
}
登入後複製

這樣一來,我們的邏輯就變成了:

if (!$user->isMember($resouce->team)) {
     throw new NotTeamMemberException($resouce->team, &#39;您无权访问该资源&#39;);
}
登入後複製

當然也可以簡寫為:

\throw_if(!$user->isMember($resouce->team), NotTeamMemberException::class, $resouce->team, &#39;您无权访问该资源&#39;);
登入後複製

問題到這裡總算以一個比較完美的方式解決了,如果你有更好的方案歡迎評論探討。

以上是分享一個Laravel異常上下文解決方案的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:learnku.com
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板