+6

Hướng dẫn xử lí exception trong Laravel

Chào các bạn, bài viết hôm nay mình sẽ giới thiệu về cách handler Exception trong Laravel.

*Trong quá trình coding, chắn hẳn bạn sẽ gặp ít nhất một trường hợp phải ném Exception cho user hoặc response dữ liệu API. Vậy xử lí Exception như thế nào chính xác, mang lại hiệu quả cao nhất ? *

Trong các version < 5.5, nếu muốn xử lí Exception, ta vào file Exceptions/Handler.php, chính xác hơn là trong method render() để xử lí. Tuy vậy, cách này không phải là cách tối ưu nhất ? Bởi vì sao ?

Ta xem ví dụ. Đây là method report() trong file Exception/Handler.php

[...]
public function report(Exception $exception)
{
    if ($exception instanceof CustomException) {
        // Do something
    }

    if ($exception instanceof MyOtherException) {
        // Do something
    }

    if ($exception instanceof MyOtherCustomException) {
        // Do something
    }

    return parent::report($exception);
}
[...]

Như các bạn thấy, ta phải xử lí rất nhiều exception trong function này. Vậy có tầm 20 Exceptions thì chúng ta phải vất vả hơn đúng không nào ?

=> Để giải quyết vấn đề này thì Laravel 5.5 đã đưa ra một cách xử lí hay hơn. Đó là, mỗi exception sẽ có method render riêng, không sử dụng chung trong file Exceptions/Handler.php. Để dễ hiểu hơn thì bạn theo dõi bài hướng dẫn mình nhé 😃

Trước khi folow đoạn tiếp theo thì mình qui ước tí nhé:

Mình sẽ handler Exception để response về API. Và format chung khi lỗi sẽ response cho API như sau:

{
    "message: [
       "Query Error",
       ....,
    ],
    "code": 400
}

1. Viết Abstract class base

1.1 Giả sử ta có 1 Abstract class base sau

<?php

namespace App\Exceptions;

use Exception;
use Illuminate\Http\Request;
use App\Http\Resources\JsonResponse;
use Log;
use Illuminate\Http\Response;

abstract class AbstractException extends Exception
{
    protected $code;
    protected $message = [];

    public function __construct($message = null, $code = Response::HTTP_INTERNAL_SERVER_ERROR)
    {
        $this->code = $code;
        $this->message = $message ?: 'Server Exception'

        parent::__construct($message, $code);
    }

    public function render(Request $request)
    {
        $json = [
            'code' => $this->code,
            'message' => [$this->message],
            'data' => null,
        ];

        return new JsonResponse($json);
    }

    public function report()
    {
        Log::emergency($this->message);
    }
}

1.2 Các thành phần trong class base

  • Message: message khi bị lỗi, thông thường là nguyên nhân lỗi
  • Code: là các HTTP status code, chẳng hạn: 400, 500, ...
  • Method render(): render kết quả (response) cho user khi bị exception. Do đây là Abstract Class base nên hầu hết các exception đều kế thừa từ class này, và các exeption con đều xử lí trong method render này.
  • Method report(): Log lại Exception để server có thể tracking lỗi

2. Xây dựng các class để hanlder các case có thể xảy ra

2.1 NotFoundException

  • Chức năng: handler trường hợp không thể tìm thấy 1 record trong database
  • Class này có 2 Arguments: Message thông báo lỗi cho user, và code trả về mã lỗi cho user, trường hợp này thường là: 404
<?php
namespace App\Exceptions;

use Illuminate\Http\Response;

class NotFoundException extends AbstractException
{
    public function __construct($message = '', $code = null)
    {
        if (!$message) {
            $message = __('exception.record_not_found');
        }

        if (!$code) {
            $code = Response::HTTP_NOT_FOUND;
        }
        parent::__construct($message, $code);
    }
}

2.2. QueryException

  • Handler khi câu query xảy ra lỗi.
  • Tương tự class ở trên, cũng có 2 param truyền vào là: message và code
<?php

namespace App\Exceptions;

use Illuminate\Http\Response;

class QueryException extends AbstractException
{
    public function __construct($message = '', $code = null)
    {
        if (!$message) {
            $message = __('exception.query_error');
        }

        if (!$code) {
            $code = Response::HTTP_BAD_REQUEST;
        }
        parent::__construct($message, $code);
    }
}

2.3. RemoteException

  • Handler cho trường hợp call API bên ngoài bị lỗi. Cũng có 2 param là message và code.
<?php

namespace App\Exceptions;

use Illuminate\Http\Response;

class RemoteException extends AbstractException
{
    public function __construct($message = '', $code = null)
    {
        if (!$message) {
            $message = __('exception.remote_error');
        }

        if (!$code) {
            $code = Response::HTTP_FORBIDDEN;
        }
        parent::__construct($message, $code);
    }
}

Tương tự cho các Exception khác nhé! Bài viết đến đây là hết rồi, hi vọng bài viết giúp ích cho các ban.

Cảm ơn !


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.