
# 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/blog
và en/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
và$id
sẽ là123
.
- Route:
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
Bài viết liên quan

9 Mẹo Hữu Ích Khi Sử Dụng Blade Trong Laravel
Author: | ADMIN |
---|

Ví dụ về các vấn đề truy vấn N+1
Author: | ADMIN |
---|

Một số lệnh Artisan Make với các tham số
Author: | ADMIN |
---|

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
Author: | ADMIN |
---|
Bài viết khác

Blade Basics
Author: | ADMIN |
---|

Hiển thị giá trị trong Blade
Author: | ADMIN |
---|

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