Laravel Routing – 8 Advanced Tips
15393

# Laravel Routing – 8 Advanced Tips

Chúng ta tất cả đều sử dụng cú pháp đơn giản của Route::get() và Route::post(), nhưng trong các dự án lớn, nó trở nên phức tạp hơn nhiều. Bài viết này sẽ tổng hợp các mẹo khác nhau cho các tình huống khác nhau.

Tip 1. Route::get() BEFORE Route::resource()

Đối với Resource Controllers, đây là một trong những sai lầm phổ biến nhất, hãy xem ví dụ này:

Route::resource('photos', 'PhotoController');
Route::get('photos/popular', 'PhotoController@method');

Khi bạn định nghĩa một route resource, Laravel tự động tạo ra nhiều route cho các hành động CRUD (Create, Read, Update, Delete)

Điều này sẽ tạo ra các route như /photos, /photos/{id}, /photos/{id}/edit, và nhiều hơn nữa. Nếu bạn có một route thêm vào, ví dụ như /photos/popular, mà bạn định nghĩa sau route resource, thì có thể xảy ra xung đột. Điều này là do Laravel ưu tiên các route định nghĩa trước. Vì vậy, nếu bạn đặt route thêm vào sau route resource, nó có thể không hoạt động như mong muốn. Trong ví dụ này, route /photos/popular có thể bị route resource /photos/{id} chặn và sẽ được gán giá trị "popular" làm tham số {id}.

Vì vậy, cú pháp đúng phải là: 

// Đặt route bổ sung trước
Route::get('photos/popular', 'PhotoController@method');

// Sau đó định nghĩa route resource
Route::resource('photos', 'PhotoController');

Tip 2. Group in Another Group

Chúng ta có lẽ đều biết rằng có thể nhóm các route bằng Route::group() và gán các middleware/prefixes khác nhau cùng các tham số khác, như các route công khai và các route yêu cầu đăng nhập.

Nhưng nếu bạn cần một tập hợp các quy tắc nhất định cho các nhóm con của những nhóm đó thì sao?

Ví dụ điển hình: bạn cần các route công khai và các route yêu cầu đăng nhập, nhưng trong nhóm các route yêu cầu đăng nhập, bạn cần tách biệt quản trị viên khỏi người dùng thông thường.

Vì vậy, bạn có thể làm điều này:

// route công khai
Route::get('/', 'HomeController@index');

// Người dùng đã đăng nhập - với middleware "auth"
Route::group(['middleware' => ['auth']], function () {

    // /user/XXX: Bên cạnh "auth", nhóm này sẽ có middleware "simple_users"
    Route::group(['middleware' => ['simple_users'], 'prefix' => 'user'], function () {
        Route::resource('tasks', 'TaskController');
    });

    // /admin/XXX: Nhóm này sẽ không có "simple_users", nhưng sẽ có "auth" và "admins"
    Route::group(['middleware' => ['admins'], 'prefix' => 'admin'], function () {
        Route::resource('users', 'UserController');
    });
});

Tip 3. Route Parameter Validation – Multi-Language Example

Một trường hợp khá điển hình là sử dụng prefix cho các route của bạn theo ngôn ngữ địa phương, ví dụ như fr/blogen/article/333. Làm thế nào để chúng ta đảm bảo rằng hai chữ cái đầu tiên đó không được sử dụng cho mục đích khác ngoài ngôn ngữ?

Chúng ta có thể xác thực trực tiếp trong route bằng tham số "where":

Route::group(['prefix' => '{locale}', 'where' => ['locale' => '[a-zA-Z]{2}']], function () {
    Route::get('/', 'HomeController@index');
    Route::get('article/{id}', 'ArticleController@show');
});

Tip 4. Routing với Subdomain Động

Đây là một tính năng đến trực tiếp từ tài liệu chính thức của Laravel, nhưng ít được sử dụng nên mình muốn đề cập đến nó.

Nếu bạn có một subdomain động, như một subdomain khác nhau cho mỗi người dùng, nó cần trở thành một biến, đúng không? Laravel đã tự động làm điều đó cho bạn. Xem ví dụ:

Route::domain('{account}.myapp.com')->group(function () {
    Route::get('user/{id}', function ($account, $id) {
        // Code xử lý
    });
});

Giải thích

  • Route::domain('{account}.myapp.com'): Định nghĩa một nhóm các route với một subdomain động {account}. Subdomain này sẽ được thay thế bằng giá trị cụ thể của từng người dùng.

  • group(function () { ... }): Định nghĩa một nhóm các route sẽ thuộc subdomain đã định nghĩa ở trên.

  • Route::get('user/{id}', function ($account, $id) { ... }): Định nghĩa một route trong nhóm này. Route này chấp nhận hai tham số: $account (giá trị của subdomain động) và $id (ID của người dùng).

Lưu ý:

  • {account} tự động được truyền như một tham số $account vào tất cả các phương thức controller bên trong nhóm route này. Vì vậy, bạn cần chấp nhận tham số này trong tất cả các phương thức controller, không quên điều này.

Ví dụ:

  • Subdomain: john.myapp.com
    • Route: john.myapp.com/user/123
    • Controller Method: function ($account, $id)
    • $account sẽ là john$id sẽ là 123.

Tip 5. Cẩn Thận với Route Model Binding Không Dùng Tiếng Anh

Đôi khi, URL cần chứa các từ không phải tiếng Anh. Ví dụ, bạn có một trang web tiếng Tây Ban Nha về sách và bạn muốn có URL như /libros cho danh sách sách, và sách cụ thể sẽ có URL như /libros/1, giống như một Resource Controller thông thường.

Nhưng trong cơ sở dữ liệu, tất cả các tên nên là tiếng Anh để "magic" của Laravel có thể hoạt động giữa dạng số ít và số nhiều, đúng không?

Vì vậy, nếu bạn tạo một model Book với migration và Controller, bạn có thể dùng lệnh sau:

php artisan make:model Book -mcr

Phím -mcr sẽ tạo một model và một resource controller. Trong Controller đó, bạn sẽ có như sau:

/**
 * Display the specified resource.
 *
 * @param  \App\Book  $book
 * @return \Illuminate\Http\Response
 */
public function show(Book $book)
{
    // ...
}

Nhưng trong routes/web.php, bạn sẽ có như sau:

Route::resource('libros', 'BookController');

Vấn đề là nó sẽ không hoạt động. Một vấn đề lớn hơn là nó sẽ không đưa ra bất kỳ lỗi nào, chỉ là biến $book sẽ rỗng, và bạn sẽ không hiểu tại sao.

Theo mô tả của Resource Controller chính thức, tên của biến phải giống với tham số ở dạng số ít:

// Thay vì
public function show(Book $book)
{
    // ...
}

// Bạn nên để
public function show(Book $libro)
{
    // ...
}

Nhưng, thành thật mà nói, trong các dự án không sử dụng tiếng Anh, tôi khuyên không nên sử dụng Route::resource và Route Model Binding. Quá nhiều "magic" không thể đoán trước, như cách Laravel sẽ "đoán" rằng dạng số ít của "libros" là "libro"?

Tip 6. API Routes – từ V1 đến V2

Hãy tưởng tượng bạn đang làm việc với dự án dựa trên API và cần phát hành phiên bản mới của API. Các endpoint cũ sẽ giữ nguyên tại api/[something], và đối với phiên bản mới, bạn sẽ sử dụng api/V2/[something].

Toàn bộ logic nằm trong app/Providers/RouteServiceProvider.php:

public function map()
{
    $this->mapApiRoutes();

    $this->mapWebRoutes();

    // ...
}

protected function mapWebRoutes()
{
    Route::middleware('web')
        ->namespace($this->namespace)
        ->group(base_path('routes/web.php'));
}

protected function mapApiRoutes()
{
    Route::prefix('api')
        ->middleware('api')
        ->namespace($this->namespace)
        ->group(base_path('routes/api.php'));
}

Như bạn có thể thấy, các route API được đăng ký trong một hàm riêng với tiền tố api/.

Vì vậy, nếu bạn muốn tạo nhóm route V2, bạn có thể tạo một tệp riêng routes/api_v2.php và làm như sau:

public function map()
{
    // ... các hàm cũ

    $this->mapApiV2Routes();
}

// Và hàm mới
protected function mapApiV2Routes()
{
    Route::prefix('api/V2')
        ->middleware('api')
        ->namespace($this->namespace)
        ->group(base_path('routes/api_v2.php'));
}

Bằng cách này, các route cũ sẽ không bị phá vỡ, và bạn chỉ cần tạo một bộ route mới.

Tip 7. Giới Hạn Tốc Độ (Rate Limiting) – Tổng Thể và cho Khách/Người Dùng

Điều này cũng xuất phát từ tài liệu chính thức, nhưng với những chi tiết ít được biết đến hơn.

Giới Hạn Tốc Độ Tổng Thể

Đầu tiên, bạn có thể giới hạn một URL được gọi tối đa 60 lần mỗi phút, với throttle:60,1.

Route::middleware('auth:api', 'throttle:60,1')->group(function () {
    Route::get('/user', function () {
        //
    });
});

Giới Hạn Tốc Độ Riêng cho Khách và Người Dùng Đã Đăng Nhập

Nhưng bạn có biết rằng bạn có thể làm điều này riêng biệt cho người dùng công khai và người dùng đã đăng nhập không?

// tối đa 10 yêu cầu mỗi phút cho khách và 60 cho người dùng đã đăng nhập
Route::middleware('throttle:10|60,1')->group(function () {
    //
});

Giới Hạn Tốc Độ cho Người Dùng Cụ Thể
Bạn cũng có thể có một trường cơ sở dữ liệu users.rate_limit và giới hạn số lượng yêu cầu cho người dùng cụ thể:

Route::middleware('auth:api', 'throttle:rate_limit,1')->group(function () {
    Route::get('/user', function () {
        //
    });
});

Tip 8. Route List and Route Caching

Xem Danh Sách Routes

Không phải tất cả chúng ta đều biết chính xác những routes nào ẩn dưới Route::resource(), hoặc dưới một số câu lệnh Route::group phức tạp hơn. Nhưng vào bất kỳ thời điểm nào, bạn có thể kiểm tra routes thực tế của mình bằng lệnh Artisan:

php artisan route:list

Lệnh này sẽ hiển thị một danh sách tất cả các routes hiện có trong ứng dụng của bạn, bao gồm tên route, phương thức HTTP, URL, tên controller và action tương ứng. Đây là một công cụ rất hữu ích để kiểm tra và gỡ lỗi cấu hình routes của bạn.

Sử Dụng Bộ Nhớ Đệm Routes

Bộ nhớ đệm routes (route caching) là một tính năng mạnh mẽ giúp cải thiện hiệu suất của ứng dụng bằng cách lưu trữ cấu hình routes trong bộ nhớ đệm. Tuy nhiên, khi bạn sử dụng bộ nhớ đệm routes, bạn cần nhớ xóa và tạo lại bộ nhớ đệm sau mỗi lần thay đổi cấu hình routes.

Để xóa bộ nhớ đệm routes:

php artisan route:clear

Sau đó, để tạo lại bộ nhớ đệm routes:

php artisan route:cache

Lệnh này sẽ lưu trữ cấu hình routes của bạn trong bộ nhớ đệm, giúp Laravel tải routes nhanh hơn trong các yêu cầu tiếp theo.

Danh mục


  1. Khác
  2. ThreeJS
  3. Ubuntu/Linux
  4. HTML/CSS
  5. Git
  6. Amazon Web Services
  7. Javascript
  8. Docker
  9. Laravel

Bài viết liên quan


9 Mẹo Hữu Ích Khi Sử Dụng Blade Trong Laravel

9 Mẹo Hữu Ích Khi Sử Dụng Blade Trong Laravel

01.08.2024
Author: ADMIN
Khám phá 9 mẹo Blade giúp bạn viết code Laravel sạch, tối ưu và chuyên nghiệp hơn. Từ @forelse, @auth, @guest, đến format ngày, tối ưu SEO – tất cả trong một bài viết súc tích, dễ áp dụng!
Ví dụ về các vấn đề truy vấn N+1

Ví dụ về các vấn đề truy vấn N+1

01.08.2024
Author: ADMIN
Tìm hiểu vấn đề N+1 Query trong Eloquent Laravel, cách phát hiện và tối ưu hóa với Eager Loading, withCount, và Strict Loading Mode để cải thiện hiệu suất ứng dụng.
Một số lệnh Artisan Make với các tham số

Một số lệnh Artisan Make với các tham số

01.08.2024
Author: ADMIN
Tổng hợp các lệnh php artisan make quan trọng trong Laravel giúp bạn tối ưu hóa quy trình phát triển! 🚀💡
Chinh phục triệu dòng dữ liệu: Các phương pháp tối ưu để nhập liệu hàng loạt trong Laravel

Chinh phục triệu dòng dữ liệu: Các phương pháp tối ưu để nhập liệu hàng loạt trong Laravel

16.02.2025
Author: ADMIN
Khám phá 10 phương pháp tối ưu nhập liệu hàng loạt trong Laravel, từ cơ bản đến nâng cao (Chunk, Lazy Collection, PDO, LOAD DATA INFILE). So sánh hiệu suất, bộ nhớ, và số lượng truy vấn để chọn giải pháp tốt nhất cho nhu cầu của bạn.

Bài viết khác

Routing

Routing

01.08.2024
Author: ADMIN
Hướng dẫn chi tiết về Basic Routing trong Laravel, từ cách định nghĩa route, sử dụng middleware, route caching đến route naming giúp tối ưu hóa ứng dụng.
Blade Basics

Blade Basics

01.08.2024
Author: ADMIN
Khám phá Blade trong Laravel: từ if-else, loops, kế thừa layout đến include sub-views. Giúp code gọn gàng, dễ quản lý và bảo trì hơn!
Hiển thị giá trị trong Blade

Hiển thị giá trị trong Blade

01.08.2024
Author: ADMIN
Hướng dẫn hiển thị biến trong Laravel Blade: escape HTML tự động, hiển thị dữ liệu thô, giá trị mặc định và cách truy xuất mảng, đối tượng. Giúp bạn tối ưu hiển thị dữ liệu một cách an toàn!
Cấu Trúc Điều Kiện và Vòng Lặp Trong Blade

Cấu Trúc Điều Kiện và Vòng Lặp Trong Blade

01.08.2024
Author: ADMIN
Khám phá các cấu trúc điều kiện và vòng lặp trong Laravel Blade. Tận dụng @if, @foreach, @forelse để hiển thị dữ liệu linh hoạt, giúp mã nguồn dễ đọc, sạch sẽ và tối ưu hơn!