Handler.php 4.68 KB
<?php

namespace App\Exceptions;

use App\Helpers\JsonResource;
use App\Support\BusinessCode;
use Hikoon\LaravelApi\Exceptions\ValidationException;
use Hikoon\LaravelApi\Support\ApiCode;
use Hikoon\LaravelApi\Support\ApiResponse;
use Hikoon\LaravelJwt\Exceptions\TokenExpiredException;
use Hikoon\LaravelJwt\Exceptions\TokenInvalidException;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Http\Exceptions\ThrottleRequestsException;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Arr;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Throwable;

class Handler extends ExceptionHandler
{
    /**
     * A list of the exception types that are not reported.
     *
     * @var array<int, class-string<\Throwable>>
     */
    protected $dontReport = [
        ValidationException::class,
        TokenExpiredException::class,
        UserStatusException::class
    ];

    /**
     * Register the exception handling callbacks for the application.
     *
     * @return void
     */
    public function register(): void
    {
        $this->reportable(static function (Throwable $e) {

        });
    }

    /**
     * @param            $request
     * @param \Throwable $e
     * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Response|\Symfony\Component\HttpFoundation\Response
     * @throws \Hikoon\LaravelApi\Exceptions\ValidationException
     * @throws \Throwable
     */
    public function render($request, Throwable $e): \Illuminate\Http\Response|JsonResponse|Response
    {
        if ($e instanceof \Illuminate\Validation\ValidationException) {
            throw new ValidationException(ApiCode::VALIDATION_ERROR, $e->getMessage());
        }

        if ($e instanceof UserStatusException) {
            throw new AuthenticationException('账号已被禁用/注销');
        }

        return parent::render($request, $e);
    }

    /**
     * @param            $request
     * @param \Throwable $e
     * @return \Illuminate\Http\JsonResponse
     */
    protected function prepareJsonResponse($request, Throwable $e): JsonResponse
    {
        if ($request->is('manage/*') || $request->is('admin/*') || $request->is('user/*')) {
            return match (true) {
                $e instanceof \Illuminate\Validation\ValidationException => ApiResponse::fail(ApiCode::VALIDATION_ERROR, $e->getMessage()->errors()->first()),
                $e instanceof TokenExpiredException, $e instanceof TokenInvalidException => ApiResponse::fail(BusinessCode::AUTHORIZED_EXPIRED_ERROR),
                $e instanceof HttpException && $e->getStatusCode() === 503 => ApiResponse::fail(ApiCode::SERVICE_UNAVAILABLE_ERROR),
                $e instanceof NotFoundHttpException => ApiResponse::fail(ApiCode::NOT_FOUND_ERROR),
                $e instanceof MethodNotAllowedHttpException => ApiResponse::fail(ApiCode::METHOD_NOT_ALLOWED_ERROR),
                $e instanceof ThrottleRequestsException => ApiResponse::fail(ApiCode::REQUEST_LIMIT_ERROR),
                default => ApiResponse::make(Arr::except($this->convertExceptionToArray($e), 'message'))->toFail(ApiCode::SERVICE_ERROR)
            };
        }

        if ($request->is('app/*')) {
            return match (true) {
                $e instanceof TokenExpiredException, $e instanceof TokenInvalidException => JsonResource::unauthenticated(JsonResource::AUTHORIZED_EXP),
                $e instanceof MethodNotAllowedHttpException => JsonResource::fail('无效的请求方式'),
                $e instanceof ThrottleRequestsException => JsonResource::fail('请求太频繁,请稍后再访问'),
                $e instanceof NotFoundHttpException => JsonResource::fail('无法找到对应资源'),
                default => JsonResource::error('服务器繁忙,请稍后再尝试...')
            };
        }


        return parent::prepareJsonResponse($request, $e);
    }

    /**
     * @inheritDoc
     */
    protected function unauthenticated($request, AuthenticationException $exception): Response
    {
        if ($request->acceptsJson()) {
            if ($request->is('manage/*') || $request->is('admin/*') || $request->is('user/*')) {
                return ApiResponse::fail(ApiCode::UNAUTHORIZED_ERROR, $exception->getMessage())->setStatusCode(401);
            }
            if ($request->is('app/*')) {
                return JsonResource::unauthenticated($exception->getMessage() ?? JsonResource::UNAUTHORIZED);
            }
        }

        return parent::unauthenticated($request, $exception);
    }
}