![]()
Middleware trong Next.js 14 là gì và tại sao bạn cần nó?
Bạn có bao giờ tự hỏi làm thế nào để kiểm soát quyền truy cập vào các trang web chỉ dành cho người dùng đã đăng nhập một cách mượt mà? Tôi nhớ hồi mới làm quen với Next.js, mình từng phải viết một đống logic kiểm tra auth ở từng component riêng lẻ.
Kết quả là code rối như mớ bòng bong. Sau đó, mình phát hiện ra Middleware – một thứ thay đổi hoàn toàn cách tiếp cận.Middleware trong Next.js 14 hoạt động như một lớp chặn giữa request và response. Nó chạy trước khi route được render, giúp kiểm tra cookie, session, token, và quyết định có cho phép truy cập hay không.Điều này cực kỳ hữu ích cho việc chuyển hướng người dùng chưa đăng nhập về trang login. Hãy tưởng tượng bạn có một ứng dụng quản lý đơn hàng.Nếu ai đó gõ thẳng đường dẫn/dashboard vào trình duyệt, Middleware sẽ kiểm tra ngay lập tức. Nếu không có token hợp lệ, người dùng sẽ bị đá về /login trong chớp mắt.Dưới đây là bảng so sánh trực quan giữa cách làm cũ và cách dùng Middleware:
| Tiêu chí | Kiểm tra auth trong từng component | Dùng Middleware |
|---|---|---|
| Thời điểm kiểm tra | Sau khi component render | Trước khi render |
| Số dòng code trung bình | 10-20 dòng mỗi file | 20-30 dòng tổng thể |
| Hiệu suất | Chậm hơn do phải render rồi mới check | Nhanh hơn nhờ kiểm tra sớm |
| Bảo trì | Khó, phải sửa nhiều file | Dễ, chỉ cần sửa một file |
| Khả năng xử lý redirect | Phức tạp, dễ gây lỗi | Đơn giản, tự động |
Nhờ có Middleware, bạn có thể tập trung logic xác thực vào một chỗ duy nhất. Sau khi hiểu được khái niệm cơ bản, việc tiếp theo là cài đặt và cấu hình như thế nào.
Cài đặt và cấu hình Middleware trong dự án Next.js 14
Để bắt đầu, bạn cần tạo file middleware.ts ở thư mục gốc của dự án (cùng cấp với thư mục app). Đừng nhầm lẫn với việc đặt nó trong app/ nhé – nó phải nằm ở root.
| Bước | Hành động | Lưu ý |
|---|---|---|
| 1 | Tạo file middleware.ts tại thư mục gốc |
Không được đặt trong app/ |
| 2 | Export hàm middleware mặc định |
Bắt buộc đúng tên |
| 3 | Import NextResponse và NextRequest |
Từ thư viện next/server |
| 4 | Định nghĩa matcher để chỉ định route |
Giúp Middleware không chạy toàn bộ |
| 5 | Xử lý logic auth và redirect | Dùng NextResponse.redirect() |
Ví dụ code cơ bản cho Middleware chuyển hướng login:
```typescript import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) { const token = request.cookies.get('auth_token')?.value; const url = request.nextUrl.clone();
if (!token && !url.pathname.includes('/login')) { url.pathname = '/login'; return NextResponse.redirect(url); }
return NextResponse.next(); }
export const config = { matcher: ['/dashboard/:path', '/profile/:path', '/admin/:path*'] }; ```
Đoạn code trên kiểm tra cookie auth_token. Nếu không có và người dùng cố vào các route như /dashboard, /profile, hay /admin, họ sẽ bị chuyển về /login.
Kỹ thuật chuyển hướng thông minh Giữ lại đường dẫn gốc
Một trong những tính năng tôi thích nhất ở Middleware là khả năng redirect kèm tham số. Thay vì chỉ chuyển về /login một cách khô khan, bạn có thể đính kèm URL gốc vào query string.
/dashboard/orders/123, bạn muốn sau khi đăng nhập, họ tự động quay lại đúng trang đó, chứ không phải trang chủ. Cách thực hiện khá đơn giản:
```typescript export function middleware(request: NextRequest) { const token = request.cookies.get('auth_token')?.value; const url = request.nextUrl.clone();
if (!token && !url.pathname.includes('/login')) { const loginUrl = new URL('/login', request.url); loginUrl.searchParams.set('redirect', request.nextUrl.pathname + request.nextUrl.search); return NextResponse.redirect(loginUrl); }
return NextResponse.next(); } ```
Ở phía trang login, bạn chỉ cần đọc tham số redirect từ URL và dùng nó làm đích đến sau khi xác thực thành công. Dưới đây là bảng so sánh giữa redirect cơ bản và redirect thông minh:
| Đặc điểm | Redirect cơ bản | Redirect thông minh |
|---|---|---|
| Trải nghiệm người dùng | Không tốt, mất vị trí | Tốt, quay lại đúng trang |
| Xử lý URL | Chỉ redirect thẳng | Kèm query string redirect |
| Code phức tạp | Đơn giản | Hơi phức tạp hơn |
| Tỷ lệ giữ chân người dùng | Thấp | Cao hơn 30-40% (theo kinh nghiệm) |
| Thời gian triển khai | 5 phút | 15 phút |
Kinh nghiệm thực tế: sau khi áp dụng redirect thông minh cho một dự án thương mại điện tử, tỷ lệ người dùng hoàn tất đăng nhập và tiếp tục mua hàng tăng lên đáng kể. Đơn giản vì họ không phải mò mẫm tìm lại trang cũ.
Xử lý các trường hợp ngoại lệ và tối ưu hiệu suất
Không phải route nào cũng cần kiểm tra auth. Các trang như /login, /register, /forgot-password hay landing page công khai nên được bỏ qua.
matcher và thêm điều kiện kiểm tra trong Middleware:
typescript
export const config = {
matcher: [
'/((?!api|_next/static|_next/image|favicon.ico|login|register|forgot-password).*)',
],
};
Regex trên loại trừ các route công khai. Nhưng lưu ý rằng matcher chỉ hoạt động ở cấp độ route, không kiểm tra được logic phức tạp.
middleware, bạn vẫn nên kiểm tra thêm. Bảng dưới đây liệt kê các route nên và không nên chặn:
| Loại route | Ví dụ | Hành động |
|---|---|---|
| Công khai | /, /about, /contact |
Cho phép truy cập |
| Auth | /login, /register |
Cho phép truy cập |
| Tài nguyên tĩnh | /_next/static/*, /favicon.ico |
Cho phép truy cập |
| API | /api/* |
Có thể kiểm tra riêng |
| Bảo vệ | /dashboard/*, /profile/* |
Kiểm tra auth |
| Admin | /admin/* |
Kiểm tra auth + role |
Về hiệu suất, Middleware trong Next.js 14 chạy ở Edge Runtime, rất nhanh. Tuy vậy, tránh đặt logic nặng như gọi database hay fetch API trong Middleware.
Việc này làm tăng thời gian phản hồi. Thay vào đó, chỉ nên kiểm tra cookie hoặc JWT token cục bộ.Nếu cần xác thực sâu hơn, hãy để route handler hoặc API route xử lý.Kết hợp Middleware với các thư viện xác thực phổ biến
Trong thực tế, ít ai tự viết logic xác thực từ đầu. Các thư viện như NextAuth.js, Clerk, Auth0, hoặc Supabase đã giải quyết phần lớn vấn đề.
Tuy vậy, Middleware vẫn đóng vai trò quan trọng trong việc điều phối luồng. Ví dụ, nếu dùng NextAuth.js, Middleware có thể kiểm tra session như sau:```typescript import { getToken } from 'next-auth/jwt'; import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server';
export async function middleware(request: NextRequest) { const token = await getToken({ req: request }); const url = request.nextUrl.clone();
if (!token && !url.pathname.includes('/login')) { url.pathname = '/api/auth/signin'; return NextResponse.redirect(url); }
return NextResponse.next(); } ```
Bảng so sánh các thư viện xác thực khi tích hợp với Middleware:
| Thư viện | Cách kiểm tra trong Middleware | Hỗ trợ JWT | Hỗ trợ session |
|---|---|---|---|
| NextAuth.js | getToken() |
Có | Có |
| Clerk | auth() từ @clerk/nextjs |
Có | Có |
| Auth0 | getSession() từ @auth0/nextjs-auth0 |
Có | Có |
| Supabase | createRouteHandlerClient() |
Có | Có |
| Firebase Auth | admin.auth().verifyIdToken() |
Có | Không |
Lời khuyên: nếu dự án của bạn có nhiều role phức tạp, hãy kết hợp Middleware với API route để kiểm tra quyền chi tiết hơn. Middleware chỉ nên làm nhiệm vụ "gác cổng", không phải "quản lý nội bộ".
Những lỗi thường gặp và cách khắc phục
Sau nhiều năm vật lộn với Next.js, tôi đã đúc kết được một số lỗi phổ biến khi dùng Middleware cho chuyển hướng login. Chia sẻ để bạn tránh mất thời gian.
Lỗi 1: Vòng lặp redirect vô tậnNguyên nhân: Middleware chuyển hướng đến /login, nhưng route /login cũng bị kiểm tra auth. Giải pháp: Thêm điều kiện loại trừ /login trong logic hoặc matcher.
Nguyên nhân: matcher không đúng cú pháp regex hoặc thiếu đường dẫn. Giải pháp: Kiểm tra kỹ regex pattern.
Nguyên nhân: Middleware chạy ở Edge, cookie có thể bị chặn bởi CORS.
Giải pháp: Đảm bảo cookie được set vớihttpOnly: false nếu cần đọc từ client. Bảng tổng hợp lỗi và thời gian sửa lỗi trung bình:
| Lỗi | Mức độ phổ biến | Thời gian sửa trung bình | Cách phòng tránh |
|---|---|---|---|
| Vòng lặp redirect | Rất cao | 30 phút | Luôn loại trừ route auth |
| Middleware không chạy | Cao | 15 phút | Test với console.log |
| Cookie không gửi kèm | Trung bình | 1 giờ | Kiểm tra cấu hình cookie |
| Lỗi khi dùng async | Thấp | 20 phút | Dùng async đúng cách |
| Xung đột với thư viện auth | Trung bình | 2 giờ | Đọc docs kỹ trước khi tích hợp |
Kinh nghiệm xương máu: luôn test Middleware trên môi trường development với nhiều tình huống khác nhau. Đừng chủ quan chỉ vì nó chạy trên local.
Tổng kết và lộ trình học tiếp theo
Middleware trong Next.js 14 là công cụ mạnh mẽ giúp bạn kiểm soát luồng chuyển hướng đăng nhập một cách gọn gàng và hiệu quả. Qua bài viết này, tôi hy vọng bạn đã nắm được:
- Cách cài đặt và cấu hình Middleware cơ bản
- Kỹ thuật redirect thông minh giữ lại URL gốc
- Cách xử lý ngoại lệ và tối ưu hiệu suất
- Tích hợp với các thư viện xác thực phổ biến
- Những lỗi thường gặp và cách khắc phục
Để đi sâu hơn, bạn có thể tìm hiểu thêm về:
- Middleware kết hợp với role-based authorization
- Sử dụng Middleware để A/B testing
- Middleware cho i18n và localization
- Middleware trong kiến trúc micro-frontend
Cuối cùng, tôi muốn nhấn mạnh rằng, dù công nghệ có thay đổi thế nào, tư duy về bảo mật và trải nghiệm người dùng vẫn là quan trọng nhất. Middleware chỉ là công cụ, còn bạn mới là người quyết định cách sử dụng nó sao cho hiệu quả.
Nếu bạn có thắc mắc hoặc muốn chia sẻ kinh nghiệm, đừng ngần ngại để lại bình luận. Chúc bạn thành công với dự án Next.js của mình!