+2

Laravel Routing

Basic Routing

use Illuminate\Support\Facades\Route;
 
Route::get('/greeting', function () {
    return 'Hello World';
});

The Default Route Files

  • Tất cả các route đã định nghĩa được tải tựu động qua App\Providers\RouteServiceProvider
  • routes/web.php định nghĩa các route cho web interface, các route này được lọc bởi web middleware group trong file app/Http/Kernel.php và được bảo vệ bởi CSRF
  • route/api.php định nghĩa các rote api và phụ thuộc vào api midddleware group và URI prefix là /api
    protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            // \Illuminate\Session\Middleware\AuthenticateSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],

        'api' => [
            'throttle:60,1',
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
    ];
  • VD route
use App\Http\Controllers\UserController;
 
Route::get('/user', [UserController::class, 'index']);

Available Router Methods

  • Laravel hỗ trợ 6 phương thức
Route::get($uri, $callback);
Route::post($uri, $callback);
Route::put($uri, $callback);
Route::patch($uri, $callback);
Route::delete($uri, $callback);
Route::options($uri, $callback);
  • Đôi khi 1 route bạn có thể khai báo nhiều method như:
Route::match(['get', 'post'], '/', function () {
    //
});
  • Hoặc route có thể bất kỳ method nào
Route::any('/', function () {
    //
});
  • Chú ý: Khi định nghĩa nhiều route chung 1 URI thì các route get, post, put, patch, delete, and options phải được định nghĩa trước các route như: match, any hoặc redirect để đảm bảo request đến route chính xác.

Dependency Injection

use Illuminate\Http\Request;
 
Route::get('/users', function (Request $request) {
    // ...
});

CSRF Protection

  • Mọi biểu mẫu HTML trỏ đến các tuyến POST, PUT, PATCH hoặc DELETE được xác định trong tệp route web phải bao gồm trường mã thông báo CSRF nếu không các reuqest sẽ bị từ chối
<form method="POST" action="/profile">
    @csrf
    ...
</form>

Redirect Routes

  • Bạn có thể dịnh nghĩa redirect route VD: /here -> /there
Route::redirect('/here', '/there');
  • Route::redirect trả về mã trạng thái 302. Bạn có thể tùy chỉnh mã trạng thái bằng tham số thứ ba tùy chọn:
Route::redirect('/here', '/there', 301);
  • Hoặc cũng có thể sử dụng method permanentRedirect để trả về status code 301:
Route::permanentRedirect('/here', '/there');

View Routes

  • Nếu bạn cần định nghĩa route chỉ có view không cần thông qua Controller thì bạn có thể dùng method view:
Route::view('/welcome', 'welcome');
 
Route::view('/welcome', 'welcome', ['name' => 'Taylor']);

The Route List

  • Để xem tất cả các route đã được định nghĩa thì có thể dùng command:
php artisan route:list

image.png

  • Theo mặc định route middleware sẽ không hiển thị trong output, nếu bạn muốn hiển thị có thể thêm optional -v:
php artisan route:list -v

image.png

  • Chỉ định URI cụ thể:
php artisan route:list --path=api

image.png

  • Bỏ qua route của thư viện (third-party packages):
php artisan route:list --except-vendor

image.png

  • Chỉ định hiển thị duy nhất route của third-party packages:
php artisan route:list --only-vendor

image.png

Route Parameters

Required Parameters

  • Tên của tham số phải được dặt trong dấu {}, tên của tham số bao gồm: chữ, số, dấu _
Route::get('/user/{id}', function ($id) {
    return 'User '.$id;
});
Route::get('/posts/{post}/comments/{comment}', function ($postId, $commentId) {
    //
});

Parameters & Dependency Injection

use Illuminate\Http\Request;
 
Route::get('/user/{id}', function (Request $request, $id) {
    return 'User '.$id;
});

Optional Parameters

Route::get('/user/{name?}', function ($name = null) {
    return $name;
});
 
Route::get('/user/{name?}', function ($name = 'John') {
    return $name;
});

Regular Expression Constraints

  • Nếu request không khớp với ràng buộc route thì sẽ return 404
Route::get('/user/{name}', function ($name) {
    //
})->where('name', '[A-Za-z]+');
 
Route::get('/user/{id}', function ($id) {
    //
})->where('id', '[0-9]+');
 
Route::get('/user/{id}/{name}', function ($id, $name) {
    //
})->where(['id' => '[0-9]+', 'name' => '[a-z]+']);
  • Có thể sử dụng các hàm mặc định:
Route::get('/user/{id}/{name}', function ($id, $name) {
    //
})->whereNumber('id')->whereAlpha('name');
 
Route::get('/user/{name}', function ($name) {
    //
})->whereAlphaNumeric('name');
 
Route::get('/user/{id}', function ($id) {
    //
})->whereUuid('id');
 
Route::get('/user/{id}', function ($id) {
    //
})->whereUlid('id');
 
Route::get('/category/{category}', function ($category) {
    //
})->whereIn('category', ['movie', 'song', 'painting']);

Global Constraints

  • Nếu muốn ràng buộc cho tất cả các route khi sử dụng cùng 1 tham số bạn cần thêm ràng buộc vào function boot() trong App\Providers\RouteServiceProvider:
/**
 * Define your route model bindings, pattern filters, etc.
 *
 * @return void
 */
public function boot()
{
    Route::pattern('id', '[0-9]+');
}
  • Khi đó các route dùng tham số id sẽ cần phải tuân thủ ràng buộc trên, vd:
Route::get('/user/{id}', function ($id) {
    // Only executed if {id} is numeric...
});

Named Routes

  • Tên của route là unique
  • Chúng ta có thể đặt tên cho route:
Route::get('/user/profile', function () {
    //
})->name('profile');
  • Tên cho controller
Route::get(
    '/user/profile',
    [UserProfileController::class, 'show']
)->name('profile');

Generating URLs To Named Routes

  • Khi đã định nghĩa tên route bạn có thể tạo URL, redirect theo tên route
// Generating URLs...
$url = route('profile');
 
// Generating Redirects...
return redirect()->route('profile');
 
return to_route('profile');
  • Trong trường hợp sử dụng tham số:
Route::get('/user/{id}/profile', function ($id) {
    //
})->name('profile');
 
$url = route('profile', ['id' => 1]);

Route::get('/user/{id}/profile', function ($id) {
    //
})->name('profile');
 
$url = route('profile', ['id' => 1, 'photos' => 'yes']);
 
// /user/1/profile?photos=yes

Inspecting The Current Route

  • Kiểm tra request hiện tại có khớp với 1 tuyến đường đã được định nghĩa hay không thông qua tên của route có thể sử dụng, ví dụ bạn có thể check thông qua middleware:
/**
 * Handle an incoming request.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Closure  $next
 * @return mixed
 */
public function handle($request, Closure $next)
{
    if ($request->route()->named('profile')) {
        //
    }
 
    return $next($request);
}

Route Groups

  • Bạn có thể nhóm các route theo middleware, Controller, domain

Middleware

Route::middleware(['first', 'second'])->group(function () {
    Route::get('/', function () {
        // Uses first & second middleware...
    });
 
    Route::get('/user/profile', function () {
        // Uses first & second middleware...
    });
});

Controllers

use App\Http\Controllers\OrderController;
 
Route::controller(OrderController::class)->group(function () {
    Route::get('/orders/{id}', 'show');
    Route::post('/orders', 'store');
});

Subdomain Routing

Route::domain('{account}.example.com')->group(function () {
    Route::get('user/{id}', function ($account, $id) {
        //
    });
});

Route Prefixes

  • Route prefix method được sử dụng để thêm tiền tố cho mỗi route trong nhóm các route
Route::prefix('admin')->group(function () {
    Route::get('/users', function () {
        // Matches The "/admin/users" URL
    });
});

Route Name Prefixes

  • Tương tự ta cũng có thể prefix theo name route
Route::name('admin.')->group(function () {
    Route::get('/users', function () {
        // Route assigned name "admin.users"...
    })->name('users');
});

Route Model Binding

  • Thông thường chúng ta hay truyền tham số ví dụ như id để lấy ra model tương ứng với id, thay vì truyền id ta có thể truyền 1 instance model tương ứng của id
  • Nếu không có mô hình nào khớp với mô hình truyền vào thì mã lỗi 404 sẽ được trả về

Implicit Binding

use App\Http\Controllers\UserController;
use App\Models\User;
 
// Route definition...
Route::get('/users/{user}', [UserController::class, 'show']);
 
// Controller method definition...
public function show(User $user)
{
    return view('user.profile', ['user' => $user]);
}

Soft Deleted Models

  • Thông thường, liên kết mô hình tiềm ẩn sẽ không truy xuất các mô hình đã bị xóa mềm, tuy nhiên bạn có thể truy xuất mô hình đã bị xóa mềm bằng phương thức withTrashed()
use App\Models\User;
 
Route::get('/users/{user}', function (User $user) {
    return $user->email;
})->withTrashed();

Explicit Binding

Form Method Spoofing

  • Html form không hỗ trỡ các method: PUT, PATCH, DELETE nên khi muốn sử dụng các method trên ta cần sử dụng như sau:
<form action="/example" method="POST">
    <input type="hidden" name="_method" value="PUT">
    <input type="hidden" name="_token" value="{{ csrf_token() }}">
</form>
  • Có thể sử dụng Blade directive
<form action="/example" method="POST">
    @method('PUT')
    @csrf
</form>

Accessing The Current Route

  • Check thông tin route hiện tại:
use Illuminate\Support\Facades\Route;
 
$route = Route::current(); // Illuminate\Routing\Route
$name = Route::currentRouteName(); // string
$action = Route::currentRouteAction(); // string

Rate Limiting

Defining Rate Limiters

  • Bạn có thể giới hạn lưu lượng truy cập cho 1 route hoặc 1 nhóm route trong 1 phút
  • Mặc định cấu hình rate limiter configurations được định nghĩa trong configureRateLimiting method ở file App\Providers\RouteServiceProvider
  • Rate limiters định nghĩa sử dụng RateLimiter facade, thông qua for method, for method chấp nhận một rate limiter name và 1 closure trả về cấu hình limit được định nghĩa.
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
 
/**
 * Configure the rate limiters for the application.
 */
protected function configureRateLimiting(): void
{
    RateLimiter::for('api', function (Request $request) {
        return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());
    });
}
  • Nếu request gửi đến vượt quá giới hạn chỉ định (số lượng request gửi đến/ 1 phút), Laravel sẽ tự động trả về HTTP status code 429, nếu bạn muốn custom mã lỗi trả về thì có thể dùng như sau:
RateLimiter::for('global', function (Request $request) {
    return Limit::perMinute(1000)->response(function (Request $request, array $headers) {
        return response('Custom response...', 429, $headers);
    });
});
  • Set limit request for route:
RateLimiter::for('uploads', function (Request $request) {
    return $request->user()->vipCustomer()
                ? Limit::none()
                : Limit::perMinute(100);
});

Segmenting Rate Limits

  • Đôi khi bạn chỉ muốn giới hạn request theo 1 điều kiện nhất định, ví dụ như giới hạn request trên 1 phút đối với 1 IP nhất định:
RateLimiter::for('uploads', function (Request $request) {
    return $request->user()->vipCustomer()
                ? Limit::none()
                : Limit::perMinute(100)->by($request->ip());
});
  • Hoặc là giới hạn cho từng ID người dùng hoặc IP như sau:
RateLimiter::for('uploads', function (Request $request) {
    return $request->user()
                ? Limit::perMinute(100)->by($request->user()->id)
                : Limit::perMinute(10)->by($request->ip());
});

Multiple Rate Limits

  • Bạn cũng có thể giới hạn một mảng rate limits, mỗi limit sẽ được áp dụng cho route phụ thuộc vào thứ tự trong mảng
RateLimiter::for('login', function (Request $request) {
    return [
        Limit::perMinute(500),
        Limit::perMinute(3)->by($request->input('email')),
    ];
});

Attaching Rate Limiters To Routes

  • Rate limiters có thể được gắn vào route hoặc nhóm route thông qua throttle middleware:
Route::middleware(['throttle:uploads'])->group(function () {
    Route::post('/audio', function () {
        //
    });
 
    Route::post('/video', function () {
        //
    });
});
  • uploads là tên của rate limiter đã được định nghĩa
  • Default bạn có thể thấy Laravel sử dụng rate limiter có tên là api cho các route api
  • Trong mảng thuộc tính $middlewareGroups:
protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],

        'api' => [
            // \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
            'throttle:api',
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
    ];
  • rate limiter có tên api đã được định nghĩa ở method configureRateLimitingtrong file app/Providers/RouteServiceProvider.php như sau:
RateLimiter::for('api', function (Request $request) {
            return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());
        });
  • Tức là mặc định trong 1 phút đối với route của api thì 1 user hoặc 1 địa chỉ ip chỉ được gửi tối đa 60 request.

Cross-Origin Resource Sharing (CORS)

Route Caching

  • Khi triển khai môi trường sản xuất nên sử dụng route cache để tăng performance
  • Khi sử chạy command artisan route:cache thì sẽ sinh ra 1 file bootstrap/cache/routes-v7.php, laravel thay vì đọc file trong folder route thì sẽ đọc file cache thay thế
php artisan route:cache
  • Clear cache thì file bootstrap/cache/routes-v7.php sẽ bị xóa
php artisan route:clear

All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí