Vòng đời request Laravel

Giống như khi vận hành một bộ máy nếu nắm được quy trình và cách thức hoạt động của bộ máy đó thì quá trình làm việc sẽ hiệu quả hơn rất nhiều. Laravel cũng vậy nếu chúng ta biết cách thức hoạt động của nó chắc chắn chúng ta sẽ tự tin làm việc với nó hơn rất nhiều. Đây là lý do bài này ra đời. Trong bài học này chúng ta sẽ tìm hiểu về vòng đời request Laravel một kiến thức được cho là nâng cao.

Lưu ý: Hãy đọc qua một lần nếu bạn thấy khó nhằn quá thì có thể bỏ qua.

1. Mô hình vòng đời request Laravel (Request Lifecycle model Laravel)

Hình dưới đây mô tả vòng đời của một request khi được gửi đến trong Laravel framework:

2. Khởi động (Bootstrap)

Đầu tiên từ phía client sẽ gửi một request (mũi tên màu xanh) đến file public/index.php, nó là đích đến của tất cả các request từ client. Dù code không nhiều nhưng nó là chính là khởi nguyên cho framework.

Mở file public/index.php lên và xem code của nó, các bạn sẽ thấy nó làm 3 nhiệm vụ chính để bootstrap framework.

1. Đăng ký cơ chế autoload (Register the auto loader)

/*
|--------------------------------------------------------------------------
| Register The Auto Loader
|--------------------------------------------------------------------------
|
| Composer provides a convenient, automatically generated class loader for
| our application. We just need to utilize it! We'll simply require it
| into the script here so that we don't have to worry about manual
| loading any of our classes later on. It feels great to relax.
|
*/


require __DIR__.'/../vendor/autoload.php';

Đoạn code này sử dụng để đăng ký autoload, một thành phần không thể thiếu trong framework. Autoload đơn giảnsẽ giúp chúng ta khởi tạo các class mà không cần phải require/include các file chứa class đó.

Chẳng hạn bạn có một project với cấu trúc thư mục như sau:

myproject/
|   User.php
|   index.php
|   autoload.php

File User.php chứa class User:

{
    public function __construct()
    {
        echo "This is User object.";
    }
}

?>

Bây giờ tại file index.php, để gọi class User ra thì cách thông thường bạn sẽ làm như thế này:


Nhưng với autoload, thì bạn không cần phải require file User.php nữa, thay vào đó:


Đây chỉ là một ví dụ đơn giản cho cơ chế autoload 

2. Chuẩn bị để khởi động ứng dụng (Prepare to bootstrap the application)

/*
|--------------------------------------------------------------------------
| Turn On The Lights
|--------------------------------------------------------------------------
|
| We need to illuminate PHP development, so let us turn on the lights.
| This bootstraps the framework and gets it ready for use, then it
| will load up this application so that we can run it and send
| the responses back to the browser and delight our users.
|
*/


$app = require_once __DIR__.'/../bootstrap/app.php';

Tại đây, Laravel framework kết nối với file bootstrap/app.php để chuẩn bị sẵn sàng cho việc chạy ứng dụng.

Mở file bootstrap/app.php các bạn sẽ thấy tại đây file này làm 3 nhiệm vụ thiết yếu để sẵn sàng cho việc bootstrap:

a. Tạo ứng dụng (Create the application)

/*
|--------------------------------------------------------------------------
| Create The Application
|--------------------------------------------------------------------------
|
| The first thing we will do is create a new Laravel application instance
| which serves as the "glue" for all the components of Laravel, and is
| the IoC container for the system binding all of the various parts.
|
*/


$app = new Illuminate\Foundation\Application(
    $_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
);

Đoạn code này đơn giản chỉ là khởi tạo class Illuminate\Foundation\Application với tham số là đường dẫn gốc của thư mục (base directory path) để thuận tiện cho việc require/include các file khác trong quá trình chạy ứng dụng.

b. Đăng ký các interface quan trọng (Bind important interfaces)

Các interface quan trọng bao gồm HTTP, CLI và trình xử lý ngoại lệ.

/*
|--------------------------------------------------------------------------
| Bind Important Interfaces
|--------------------------------------------------------------------------
|
| Next, we need to bind some important interfaces into the container so
| we will be able to resolve them when needed. The kernels serve the
| incoming requests to this application from both the web and CLI.
|
*/


$app->singleton(
    Illuminate\Contracts\Http\Kernel::class,
    App\Http\Kernel::class
);


$app->singleton(
    Illuminate\Contracts\Console\Kernel::class,
    App\Console\Kernel::class
);


$app->singleton(
    Illuminate\Contracts\Debug\ExceptionHandler::class,
    App\Exceptions\Handler::class
);
c. Trả về đối tượng ứng dụng (Return the application)
/*
|--------------------------------------------------------------------------
| Return The Application
|--------------------------------------------------------------------------
|
| This script returns the application instance. The instance is given to
| the calling script so we can separate the building of the instances
| from the actual running of the application and sending responses.
|
*/


return $app;

Tới đây quá trình chuẩn bị đã hoàn tất cho việc bootstrap framework rồi đấy các bạn ạ.

3. Chạy ứng dụng (Run the application)

/*
|--------------------------------------------------------------------------
| Run The Application
|--------------------------------------------------------------------------
|
| Once we have the application, we can handle the incoming request
| through the kernel, and send the associated response back to
| the client's browser allowing them to enjoy the creative
| and wonderful application we have prepared for them.
|
*/


$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
$response = $kernel->handle(
    $request = Illuminate\Http\Request::capture()
);

$response->send();
$kernel->terminate($request, $response);

Đoạn này sẽ nhận app object vừa trả về và thực hiện các công đoạn để chạy ứng dụng, bao gồm 2 công đoạn chính:

  • Xử lý request
  • Trả về response

3. HTTP/Console Kernel

Tiếp theo, request sẽ được gửi đến HTTP Kernel hoặc Console Kernel, tùy thuộc vào request được gửi từ đâu.Cái chúng ta chỉ quan tâm đến HTTP Kernel nằm ở file app/Http/Kernel.php mà thôi.

  • HTTP Kernel kế thừa lớp Illuminate\Foundation\Http\Kernel, class này thực việc các công việc trước khi request được thực thi như cấu hình xử lý lỗi, cấu hình logger, xác định môi trường ứng dụng và một số công việc khác.
  • HTTP Kernel cũng thực hiện một số middleware mặc định của Laravel buộc các request phải vượt qua trước khi được ứng dụng xử lý như kiểm tra ứng dụng có đang ở chế độ bảo trì hay không, xác thực CSRF các thao tác với HTTP session...
  • HTTP Kernel như một chiếc "hộp đen" của ứng dụng, hoạt động theo cơ chế đơn giản: nhận request và trả về response.

4. Service providers

Một trong loạt công việc quan trọng nhất của HTTP Kernel chính là load các service provider. Tất cả các service provider được cấu hình trong file config/app.php. Quá trình load các service provider sẽ phải trải qua hai quá trình:

  • Đăng ký service provider (Register service provider)
  • Khởi động service provider (Bootstrap service provider)

Các service provider sẽ khởi động nhiều thành phần khác nhau của framework như database, validation, router... Chính vì thế mà nó đóng vai trò thiết yếu trong quá trình chạy ứng dụng Laravel.

5. Router

Sau khi hoàn tất load service provider, các request sẽ được gửi đến router. Cách hoạt động của router rất dễ hiểu, việc này giống như bạn tìm nhà cho một đứa trẻ đi lạc vậy. Công việc của router sẽ kiểm tra tất cả các route đã được khai báo trong các file ở thư mục routes so với request được gửi đến. Nếu khớp hoàn toàn với một route nào đó thì sẽ có hai hướng xử lý. Hãy quan sát mô hình ở phía trên, tại chốt chặn route có hai hướng rẽ:

  • Route -> Middleware -> Controller/Action
  • Route -> Controller/Action

Vì sao có hai hướng xử lý như vậy? Bởi vì khi khai báo route, Laravel cho phép ta có thể ràng buộc request đi qua bằng các middleware tự tạo. Chính vì vậy mà tùy vào mỗi route có ràng buộc middleware hay không nên mình chia hai hướng xử lý như vậy để bao quát.

6. Middleware

Như đã đề cập ở trên, để ứng dụng có thể xử lý được request mà route đã đăng ký middleware thì đương nhiên ứng dụng phải vượt qua nó. Tại đây, middleware sẽ xử lý logic theo những ràng buộc mà coder đặt ra để quyết định xem request đó có được đi tiếp hay là không.

Chẳng hạn như có một request với đường dẫn là http://localhost:8000/login, một coder muốn ràng buộc rằng nếu tồn tại session/cookie đăng nhập của client thì khi vào request này sẽ chuyển về trang chủ, còn nếu không thì vẫn hiển thị form đăng nhập để client tiếp tục. Đây là lúc sử dụng middleware để ràng buộc.

7. Phương thức xử lý (Handle method)

Có hai phương thức xử lý request đó chính là

  •  Controller 
  • Action (Closure object).

2 phương thức này nhìn chung hoạt động như nhau nhưng cách thể hiện và hiệu năng lại khác nhau.

Controller là thành phần của mô hình MVC nên về tối ưu và hiệu năng hơn hẳn action, rất dễ dàng quản lý và mở rộng.

Action lại dành cho những phương thức xử lý ngắn gọn như trả về một view, hay return một object, array... thường dành cho test hoặc trong quá trình học.

Tuy nhiên cả hai phương thức này sau cùng cũng sẽ trả về response sau khi xử lý xong request, theo cơ chế "hộp đen" của HTTP Kernel.

8. Phương thức trả về (Return method)

Trên mô hình rất dễ dàng nhận thấy có hai mũi tên màu đỏ trả về phía client, đó chính là response. Nhưng sao lại có hai hướng như vậy, đó là do chúng ta có hai cách thức để trả về response:

  • Trả về response thông qua View
  • Trả về response không thông qua View

Thực tế  hai hình thức này cũng không có nhiều điểm khác biệt, chia nhánh như vậy để đồng bộ mô hình mà thôi. View chứa các template đã được khai báo sẵn, khi trả về chỉ kèm theo các tham số tùy biến. Trả về response thông qua View chỉ thường áp dụng khi load giao diện, phương thức hay dùng vẫn là phương thức còn lại.

9. Lời kết:

Việc nắm được vòng đời request Laravel là không bắt buộc thế nhưng ngược lại nếu bạn nắm vững được nó chắc chắn việc tiếp xúc và sử dụng Laravel sẽ dễ dàng hơn nhiều. Chúc cá bạn thành công!


Bình luận