Nhảy tới nội dung

Middleware

Middleware cho phép xử lý HTTP request trước khi đến controller và response trước khi trả về client.

Tạo Middleware

<?php

namespace App\Middleware;

use Vietiso\Core\Http\Request;
use Vietiso\Core\Http\Response;
use Closure;

class AuthMiddleware
{
public function handle(Request $request, Closure $next): Response
{
// Xử lý trước khi đến controller
if (!$request->bearerToken()) {
return Response::json(['error' => 'Unauthorized'], 401);
}

// Gọi middleware tiếp theo hoặc controller
$response = $next($request);

// Xử lý sau khi controller trả về (nếu cần)
return $response;
}
}

Đăng ký Global Middleware

Đăng ký trong file vietiso ở thư mục gốc:

<?php
// vietiso

use Vietiso\Core\Middleware\MiddlewareCollection;
use App\Middleware\AuthMiddleware;
use App\Middleware\CorsMiddleware;
use App\Middleware\LogMiddleware;

App::getInstance()
->setBasePath(__DIR__)
->withMiddleware(static function (MiddlewareCollection $middlewares): void {
// Đăng ký global middleware - áp dụng cho tất cả routes
$middlewares->use([
LogMiddleware::class,
CorsMiddleware::class,
AuthMiddleware::class,
]);

// Hoặc thêm từng cái
$middlewares->add(RateLimitMiddleware::class);

// Đăng ký alias để dùng với #[Middleware('auth')]
$middlewares->alias('auth', AuthMiddleware::class);
$middlewares->alias('admin', AdminMiddleware::class);
})
->start();

Middleware mặc định của Framework

use Vietiso\Core\Middleware\ConvertEmptyStringsToNull;
use Vietiso\Core\Middleware\TrimStrings;
use Vietiso\Core\Http\Middleware\HandleException;
use Vietiso\Core\Middleware\HandleCors;

$middlewares->use([
HandleCors::class, // Xử lý CORS
HandleException::class, // Xử lý exceptions
TrimStrings::class, // Trim whitespace
ConvertEmptyStringsToNull::class, // '' -> null
]);

Middleware cho Module

Thêm middleware chỉ áp dụng cho 1 module:

$middlewares->add(BookingLogMiddleware::class, 'booking');

Sử dụng trên Route

use Vietiso\Core\Route\Attributes\Get;
use Vietiso\Core\Route\Attributes\Middleware;

#[Get('/dashboard')]
#[Middleware('auth')]
public function dashboard() {}

// Nhiều middleware
#[Get('/admin')]
#[Middleware('auth', 'admin')]
public function admin() {}

Sử dụng trên Controller

use Vietiso\Core\Route\Attributes\Middleware;

#[Middleware('auth')]
class AdminController
{
#[Get('/dashboard')]
public function dashboard() {}

#[Get('/settings')]
public function settings() {}
}

Loại trừ Middleware

use Vietiso\Core\Route\Attributes\WithoutMiddleware;

#[Middleware('auth')]
class ApiController
{
#[Get('/protected')]
public function protected() {}

#[Get('/public')]
#[WithoutMiddleware('auth')]
public function public() {}
}

Ví dụ Middleware

CORS Middleware

<?php

namespace App\Middleware;

use Vietiso\Core\Http\Request;
use Vietiso\Core\Http\Response;
use Closure;

class CorsMiddleware
{
public function handle(Request $request, Closure $next): Response
{
if ($request->isMethod('OPTIONS')) {
return $this->handlePreflight();
}

$response = $next($request);

return $response
->withHeader('Access-Control-Allow-Origin', '*')
->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
->withHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
}

private function handlePreflight(): Response
{
return Response::make('', 204)
->withHeader('Access-Control-Allow-Origin', '*')
->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
->withHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
}
}

Rate Limit Middleware

<?php

namespace App\Middleware;

use Vietiso\Core\Http\Request;
use Vietiso\Core\Http\Response;
use Vietiso\Core\Redis\Facade\Redis;
use Closure;

class RateLimitMiddleware
{
public function handle(Request $request, Closure $next): Response
{
$key = 'rate_limit:' . $request->ip();
$attempts = Redis::incr($key);

if ($attempts === 1) {
Redis::expire($key, 60);
}

if ($attempts > 60) {
return Response::json(['error' => 'Too many requests'], 429);
}

return $next($request);
}
}

Log Request Middleware

<?php

namespace App\Middleware;

use Vietiso\Core\Http\Request;
use Vietiso\Core\Http\Response;
use Vietiso\Core\Log\Facade\Log;
use Closure;

class LogRequestMiddleware
{
public function handle(Request $request, Closure $next): Response
{
$start = microtime(true);

$response = $next($request);

$duration = round((microtime(true) - $start) * 1000, 2);

Log::info('Request', [
'method' => $request->method(),
'uri' => $request->uri(),
'status' => $response->getStatusCode(),
'duration' => $duration . 'ms',
]);

return $response;
}
}