Heim > PHP-Framework > Laravel > Hauptteil

Teilen Sie eine Laravel-Ausnahmekontextlösung

藏色散人
Freigeben: 2021-01-22 09:05:13
nach vorne
1955 Leute haben es durchsucht

Kürzlich ist im Projekt eine Situation aufgetreten, wenn wir auf einen Benutzer stoßen, der keine Berechtigung zum Zugriff auf bestimmte Informationen hat. Wenn beispielsweise auf eine Teamressource zugegriffen wird und Nichtmitglieder darauf zugreifen, wird eine Meldung angezeigt wird aufgefordert: Wenn Sie kein Mitglied des [xxxxxx]-Teams sind, können Sie es vorübergehend nicht anzeigen. Sie können gleichzeitig den codierten Teamnamen und angeben Die Verknüpfungsschaltfläche muss jedoch angezeigt werden. Die Logik der Schnittstelle besteht jedoch darin, direkt <code>abzubrechen:

Das Antwortergebnis lautet wie folgt:
HTTP/1.0 403 Forbidden{
    "message": "您无权访问该资源"}
Nach dem Login kopieren
Es ist für uns unmöglich, HTML zur Anzeige zu verwenden Die Front-End-Eingabeaufforderungsseite ist zu stark und verstößt gegen das Prinzip der Front-End- und Back-End-Trennung. Unser Ziel ist es, das folgende Format zurückzugeben, um das Problem zu lösen:

HTTP/1.0 403 Forbidden{
    "message": "您无权访问该资源",
    "team": {
        "id": "abxT8sioa0Ms",
        "name": "CoDesign****"
    }}
Nach dem Login kopieren

Übertragen Sie Daten durch Übertragen des Kontexts, was die freie Kombination von Front-End-Studenten erleichtert. 您不是 [xxxxxx] 团队的成员,暂时无法查看,可<申请加入>,同时需要显示打码后的团队名称,以及加入按钮,可是接口方的逻辑是当没有权限时直接 abort 了:

- 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);
+ }
Nach dem Login kopieren

得到的响应结果如下:

 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));
 }
Nach dem Login kopieren

我们不可能将 message 用 html 来完成前端提示页的展示,这样耦合性太强,违背了前后端分离的原则。我们的目标是返回如下的格式即可解决:

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);
    }
    //...
Nach dem Login kopieren

通过携带上下文的方法传递数据,方便了前端同学自由组合。

开始改造

当然这并不是什么复杂的事情,直接修改原来的 abort_if 即可解决:

$ ./artisan make:exception NotTeamMemberException
Nach dem Login kopieren

这样看起来解决了问题,可是试想一下,如果是在闭包里面检测到异常想要退出,上面这种 return 式的写法就会比较难搞了,毕竟 return 只会终止最近的上下文环境,我们还是希望像 abort 一样能终止整个应用的执行,再进行另一番改造。

优化实现

看了 abort 源码,我发现它的第一个参数其实支持 SymfonyComponentHttpFoundationResponse 实例,而上面我们 return 的结果就是它的实例,所以我们只需要改成这样就可以了:

<?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
        );
    }
}
Nach dem Login kopieren

看起来实现了异常中断,可是新的问题来了,如果需要复用的时候还是比较尴尬,这段代码将会重复出现在各种有此权限判断的地方,这并不是我们想要的。

逻辑复用

为了达到逻辑复用,看了 AppExceptionsHandler 的实现,发现父类的 render 方法还有这么一个设计:

if (!$user->isMember($resouce->team)) {
     throw new NotTeamMemberException($resouce->team, &#39;您无权访问该资源&#39;);
}
Nach dem Login kopieren

所以,我们可以将这个逻辑抽离为一个独立的异常类,实现 render

Starten Sie die Transformation

Natürlich ist dies keine komplizierte Angelegenheit, ändern Sie einfach den ursprünglichen abort_if, um ihn zu lösen it:

\throw_if(!$user->isMember($resouce->team), NotTeamMemberException::class, $resouce->team, &#39;您无权访问该资源&#39;);
Nach dem Login kopieren

Das scheint das Problem zu lösen, aber stellen Sie sich vor, wenn beim Schließen eine Ausnahme erkannt wird und Sie beenden möchten, wird der obige return-Schreibstil schließlich schwieriger return beendet nur den neuesten Kontext. Wir hoffen immer noch, die Ausführung der gesamten Anwendung wie abort zu beenden und dann eine weitere Transformation durchzuführen.

Optimierte Implementierung

🎜🎜Nachdem ich mir den Quellcode von abort angesehen hatte, stellte ich fest, dass der erste Parameter tatsächlich unterstützt wird SymfonyComponentHttpFoundationResponse-Instanz, und das Ergebnis unserer return oben ist ihre Instanz, daher müssen wir sie nur wie folgt ändern: 🎜rrreee🎜Es scheint, dass Ausnahme-Interrupts implementiert sind, aber Das neue Problem besteht darin, dass es immer noch peinlich ist, wenn dieser Code an verschiedenen Stellen angezeigt wird. Dies ist nicht das, was wir wollen. 🎜🎜🎜Logische Wiederverwendung🎜🎜🎜Um eine logische Wiederverwendung zu erreichen, habe ich mir die Implementierung von AppExceptionsHandler angesehen und festgestellt, dass die render -Methode der übergeordneten Klasse ein solches Design hat : 🎜rrreee🎜 Daher können wir diese Logik in eine unabhängige Ausnahmeklasse extrahieren und die Methode render implementieren: 🎜🎜Wir erstellen zunächst eine Ausnahmeklasse: 🎜rrreee🎜Der Implementierungscode lautet wie folgt: 🎜rrreee 🎜Auf diese Weise wird unsere Logik zu: 🎜rrreee🎜Natürlich kann es auch abgekürzt werden als: 🎜rrreee🎜Das Problem ist endlich auf eine perfektere Weise gelöst, bitte kommentieren und diskutieren Sie es. 🎜

Das obige ist der detaillierte Inhalt vonTeilen Sie eine Laravel-Ausnahmekontextlösung. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:learnku.com
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage