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;
}
}