>PHP 프레임워크 >Laravel >Laravel 예외 컨텍스트 솔루션 공유

Laravel 예외 컨텍스트 솔루션 공유

藏色散人
藏色散人앞으로
2021-01-21 11:05:061982검색

최근 프로젝트에서 특정 정보에 대한 액세스 권한이 없는 사용자를 만나면 자세한 이유를 알려주시기 바랍니다. 예를 들어 팀 리소스에 액세스하고 비회원이 액세스하는 경우 메시지가 표시됩니다. 당신이 [xxxxxx] 팀의 구성원이 아니면 일시적으로 볼 수 없습니다. 동시에 a56d7a13b72d2387ce82286e39313906을 할 수 있습니다. 참여 버튼이 표시되어야 합니다. 그러나 인터페이스의 논리는 직접 중단하는 것입니다.

abort_if(!$user->isMember($resouce->team), 403, '您无权访问该资源');
응답 결과는 다음과 같습니다.
HTTP/1.0 403 Forbidden{
    "message": "您无权访问该资源"}
HTML을 사용하여 표시하는 것은 불가능합니다. 이 결합은 너무 강력하여 프런트엔드와 백엔드 분리 원칙을 위반합니다. 우리의 목표는 문제를 해결하기 위해 다음 형식을 반환하는 것입니다.

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

프론트 엔드 학생들의 자유로운 조합을 촉진하는 컨텍스트를 전달하여 데이터를 전송합니다. 您不是 [xxxxxx] 团队的成员,暂时无法查看,可589dbe80f52208edfac91e23a0ccf85e,同时需要显示打码后的团队名称,以及加入按钮,可是接口方的逻辑是当没有权限时直接 abort 了:

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

得到的响应结果如下:

 if (!$user->isMember($resouce->team)) {
    abort(response()->json([
        'message' => '您无权访问该资源',
        'team' => [
            'id' => $resouce->team_id,
            'name'=> $resouce->team->desensitised_name,
        ]
    ], 403));
 }

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

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);
    }
    //...

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

开始改造

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

$ ./artisan make:exception NotTeamMemberException

这样看起来解决了问题,可是试想一下,如果是在闭包里面检测到异常想要退出,上面这种 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
        );
    }
}

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

逻辑复用

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

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

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

변환 시작

물론 이것은 복잡한 문제가 아닙니다. 원래 abort_if를 수정하여 해결하세요. it :

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

이렇게 하면 문제가 해결되는 것 같지만, 클로저에서 예외가 감지되어 종료하려는 경우 위의 return 작성 스타일이 결국 더 어려워질 것이라고 상상해 보세요. return은 최신 컨텍스트만 종료합니다. 우리는 여전히 abort와 같이 전체 애플리케이션의 실행을 종료한 다음 또 다른 변환을 수행하기를 희망합니다.

최적화된 구현

🎜🎜abort의 소스 코드를 살펴본 후 첫 번째 매개변수가 실제로 지원하는 것을 발견했습니다. SymfonyComponentHttpFoundationResponse 인스턴스이고 위의 return 결과가 해당 인스턴스이므로 다음으로만 변경하면 됩니다. 🎜rrreee🎜예외 인터럽트가 구현된 것 같지만, 새로운 문제는 재사용해야 한다면 여전히 당황스럽다는 것입니다. 이 코드는 이 권한이 판단되는 여러 위치에서 반복적으로 나타납니다. 🎜🎜🎜로직 재사용🎜🎜🎜로직 재사용을 달성하기 위해 AppExceptionsHandler 구현을 살펴본 결과 상위 클래스의 render 메서드가 이러한 디자인을 가지고 있음을 발견했습니다. : 🎜rrreee🎜 따라서 이 로직을 독립적인 예외 클래스로 추출하고 render 메서드를 구현할 수 있습니다. 🎜🎜먼저 예외 클래스를 만듭니다. 🎜rrreee🎜구현 코드는 다음과 같습니다. 🎜rrreee 🎜이렇게 하면 우리의 논리는 다음과 같이 됩니다. 🎜rrreee🎜물론 다음과 같이 축약할 수도 있습니다. 🎜rrreee🎜 문제는 마침내 비교적 완벽한 방법으로 해결되었습니다. 더 나은 해결책이 있다면 댓글을 달고 토론해 주세요. 🎜

위 내용은 Laravel 예외 컨텍스트 솔루션 공유의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 learnku.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제