Laravel nâng cao

Laravel Middleware: Kiến trúc và cách viết Custom Middleware hiệu quả

Đi sâu vào cơ chế Onion Architecture của Laravel Middleware. Hướng dẫn viết Custom Middleware xử lý logging, phân quyền và tối ưu response.

newspaper

Thắng Nguyễn

8 tháng 1, 2026 schedule 4 phút đọc
Laravel Middleware: Kiến trúc và cách viết Custom Middleware hiệu quả
Featured Image

Khi phỏng vấn các bạn ứng viên Laravel mid/senior, tôi hay hỏi: “Middleware hoạt động như thế nào?”. Đa số trả lời: “Nó đứng giữa Request và Controller để chặn hoặc cho qua”. Đúng, nhưng chưa đủ.

Hiểu sâu về Onion Architecture (Kiến trúc củ hành) của Middleware sẽ giúp bạn làm chủ được flow của ứng dụng, đặc biệt là khi cần can thiệp vào Response hoặc xử lý các tác vụ ngầm (background tasks) ngay trong lifecycle của request.

Mô hình Củ hành (Onion)

Hãy tưởng tượng request như một mũi tên bắn xuyên qua củ hành.

  • Lớp vỏ: Global Middleware (Check maintenance mode, Trim strings…).
  • Lớp giữa: Group Middleware (Web/API group, Session start, CSRF verify…).
  • Lớp trong: Route Middleware (Auth check, Role check…).
  • Nhân: Controller xử lý chính.

Mũi tên đi vào (Request) -> Chạm Nhân -> Bật ngược ra (Response). Tức là Middleware có cơ hội can thiệp 2 lần: Trước khi vào Controller và Sau khi có Response.

public function handle($request, Closure $next)
{
    // 1. BEFORE: Code chạy TRƯỚC khi vào Controller
    // Ví dụ: Kiểm tra user ban, log request time start
    
    $response = $next($request); // <-- Đi sâu vào lớp tiếp theo/Controller

    // 2. AFTER: Code chạy SAU khi Controller return Response
    // Ví dụ: Kèm thêm header, log request time end
    
    return $response;
}

Terminable Middleware: Vũ khí bị lãng quên

Có một tính năng cực hay mà ít dev dùng: terminate(). Đôi khi bạn muốn log lại hoạt động user, nhưng việc ghi log vào database tốn 200ms. Bạn không muốn user phải chờ thêm 200ms đó.

Giải pháp: Dùng terminate. Method này chạy sau khi response đã được gửi xuống trình duyệt. User đã thấy web load xong rồi, server mới âm thầm chạy logic này.

class LogUserActivity
{
    public function handle($request, Closure $next)
    {
        return $next($request);
    }

    public function terminate($request, $response)
    {
        // Code này chạy sau khi user đã nhận phản hồi
        // Thoải mái query DB, bắn API logging mà không sợ delay web
        ActivityLog::create([
            'url' => $request->fullUrl(),
            'status' => $response->getStatusCode(),
            'time' => microtime(true) - LARAVEL_START,
        ]);
    }
}

Lưu ý: Để terminate hoạt động, server của bạn phải dùng FastCGI (như PHP-FPM), điều này mặc định hầu hết server đều có.

Best Practices khi viết Middleware

  1. Single Responsibility: Mỗi middleware chỉ làm một việc. Đừng gộp check Auth và check Role vào chung một cái.
  2. Fail Fast: Nếu request không hợp lệ (ví dụ thiếu token), hãy return response()->json(...) hoặc abort() ngay lập tức ở phần Before, đừng cho nó chui sâu vào trong tốn tài nguyên.
  3. Alias ngắn gọn: Đặt tên alias (trong bootstrap/app.php hoặc Kernel.php) gợi nhớ. Ví dụ role:server dễ đọc hơn CheckUserRole::class.

Ví dụ thực tế: Middleware chuẩn hóa Response

Dự án của tôi luôn có một middleware bọc ngoài cùng để đảm bảo mọi JSON response trả về đều có format chuẩn { data, status, message }, kể cả khi dev lười chỉ return array.

public function handle($request, Closure $next)
{
    $response = $next($request);

    // Chỉ can thiệp nếu là JSON response
    if ($response instanceof JsonResponse) {
        $data = $response->getData(true);
        
        // Nếu data chưa có cấu trúc chuẩn thì bọc lại
        if (!isset($data['status'])) {
            $response->setData([
                'status' => $response->getStatusCode() < 400,
                'data' => $data,
                'message' => 'Success'
            ]);
        }
    }

    return $response;
}

Kết luận

Middleware không chỉ là cái “cổng bảo vệ”. Nó là công cụ mạnh mẽ để quản lý Cross-Cutting Concerns (những vấn đề cắt ngang hệ thống như Logging, Caching, Auth) một cách tập trung và gọn gàng. Hãy tận dụng tối đa terminate() để tăng tốc độ phản hồi cho user.

quizQuick Quiz
Câu 1/3

Cơ chế hoạt động của Middleware trong Laravel được ví như hình ảnh gì?

history_edu Góc học tập & giải trí

Thử Thách Kiến Thức Lịch Sử?

Khám phá hàng trăm câu hỏi trắc nghiệm lịch sử thú vị tại HistoQuiz. Vừa học vừa chơi, nâng cao kiến thức ngay hôm nay!

Chơi Ngay arrow_forward