Middleware adalah lapisan perantara yang memungkinkan Anda untuk memfilter HTTP request dan response dalam aplikasi NexaUi.
Middleware adalah mekanisme untuk memfilter HTTP request yang masuk ke aplikasi Anda. Middleware dapat digunakan untuk berbagai tugas seperti:
Middleware bekerja seperti lapisan bawang, di mana request harus melewati setiap lapisan sebelum mencapai controller, dan response harus melewati lapisan yang sama dalam urutan terbalik sebelum dikirim kembali ke client.
Untuk membuat middleware di NexaUi, Anda perlu membuat class yang mengimplementasikan interface MiddlewareInterface
:
namespace App\Middleware;
use App\System\Http\Request;
use App\System\Http\Response;
use App\System\Middleware\MiddlewareInterface;
use App\System\Http\RequestHandler;
class AuthMiddleware implements MiddlewareInterface
{
public function process(Request $request, RequestHandler $handler): Response
{
// Periksa apakah pengguna sudah login
if (!$this->isAuthenticated()) {
// Redirect ke halaman login jika belum login
return new RedirectResponse('/login');
}
// Lanjutkan ke middleware berikutnya atau controller
return $handler->handle($request);
}
private function isAuthenticated(): bool
{
return isset($_SESSION['user_id']);
}
}
Ada beberapa cara untuk mendaftarkan middleware di NexaUi:
Middleware global akan dijalankan pada setiap request:
// Di file bootstrap atau konfigurasi
$app->addMiddleware(new \App\Middleware\LoggingMiddleware());
$app->addMiddleware(new \App\Middleware\SecurityHeadersMiddleware());
Middleware dapat diterapkan pada route tertentu:
// Di file routes/web.php
$router->group(['middleware' => [\App\Middleware\AuthMiddleware::class]], function($router) {
$router->get('/dashboard', 'DashboardController@index');
$router->get('/profile', 'ProfileController@show');
});
// Atau pada route individual
$router->get('/admin', 'AdminController@index')
->middleware(\App\Middleware\AdminMiddleware::class);
Middleware juga dapat ditambahkan di level controller:
class UserController extends NexaController
{
protected function init(): void
{
parent::init();
// Tambahkan middleware ke semua action di controller ini
$this->addMiddleware(new \App\Middleware\AuthMiddleware());
// Middleware hanya untuk action tertentu
$this->addMiddleware(new \App\Middleware\AdminMiddleware(), ['update', 'delete']);
}
}
Anda dapat mengelompokkan beberapa middleware menjadi satu grup untuk memudahkan penggunaan:
// Di file konfigurasi middleware
$app->middlewareGroups([
'web' => [
\App\Middleware\StartSession::class,
\App\Middleware\VerifyCsrfToken::class,
],
'api' => [
\App\Middleware\ThrottleRequests::class,
\App\Middleware\FormatJsonResponse::class,
]
]);
// Penggunaan di routes
$router->group(['middleware' => 'web'], function($router) {
// Routes dengan middleware web group
});
$router->group(['middleware' => 'api'], function($router) {
// Routes dengan middleware api group
});
Urutan middleware sangat penting karena menentukan urutan eksekusi. Middleware yang didaftarkan lebih awal akan dieksekusi lebih dulu:
// Urutan eksekusi: LoggingMiddleware -> AuthMiddleware -> RateLimitMiddleware
$app->addMiddleware(new \App\Middleware\LoggingMiddleware()); // Dieksekusi pertama
$app->addMiddleware(new \App\Middleware\AuthMiddleware()); // Dieksekusi kedua
$app->addMiddleware(new \App\Middleware\RateLimitMiddleware()); // Dieksekusi ketiga
Anda juga dapat menentukan prioritas secara eksplisit:
$app->addMiddleware(new \App\Middleware\CriticalMiddleware(), null, 100); // Prioritas tinggi
$app->addMiddleware(new \App\Middleware\NormalMiddleware(), null, 50); // Prioritas normal
$app->addMiddleware(new \App\Middleware\LowPriorityMiddleware(), null, 10); // Prioritas rendah
namespace App\Middleware;
class AuthMiddleware implements MiddlewareInterface
{
public function process(Request $request, RequestHandler $handler): Response
{
if (!isset($_SESSION['user_id'])) {
return new RedirectResponse('/login');
}
return $handler->handle($request);
}
}
namespace App\Middleware;
class CorsMiddleware implements MiddlewareInterface
{
public function process(Request $request, RequestHandler $handler): Response
{
$response = $handler->handle($request);
return $response->withHeaders([
'Access-Control-Allow-Origin' => '*',
'Access-Control-Allow-Methods' => 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers' => 'Content-Type, Authorization'
]);
}
}
namespace App\Middleware;
class RateLimitMiddleware implements MiddlewareInterface
{
private $maxRequests = 60;
private $timeWindow = 60; // dalam detik
public function process(Request $request, RequestHandler $handler): Response
{
$ip = $request->getClientIp();
$key = "rate_limit:{$ip}";
$count = $this->getRequestCount($key);
if ($count >= $this->maxRequests) {
return new JsonResponse([
'error' => 'Too many requests'
], 429);
}
$this->incrementRequestCount($key);
return $handler->handle($request);
}
// Implementasi metode helper
}
Beberapa middleware mungkin perlu melakukan operasi setelah response dikirim ke client. Untuk ini, Anda dapat menggunakan interface TerminableMiddlewareInterface
:
namespace App\Middleware;
use App\System\Http\Request;
use App\System\Http\Response;
use App\System\Middleware\TerminableMiddlewareInterface;
class LoggingMiddleware implements MiddlewareInterface, TerminableMiddlewareInterface
{
public function process(Request $request, RequestHandler $handler): Response
{
// Catat waktu mulai
$startTime = microtime(true);
// Proses request
$response = $handler->handle($request);
// Simpan waktu mulai di response
$response = $response->withAttribute('start_time', $startTime);
return $response;
}
public function terminate(Request $request, Response $response): void
{
// Operasi ini dijalankan setelah response dikirim ke client
$startTime = $response->getAttribute('start_time');
$duration = microtime(true) - $startTime;
// Log durasi request
$this->logger->info(sprintf(
'Request to %s completed in %.2fms',
$request->getUri()->getPath(),
$duration * 1000
));
}
}
Berikut adalah contoh implementasi lengkap dari middleware dalam aplikasi NexaUi:
// system/Middleware/MiddlewareInterface.php
namespace App\System\Middleware;
use App\System\Http\Request;
use App\System\Http\Response;
use App\System\Http\RequestHandler;
interface MiddlewareInterface
{
public function process(Request $request, RequestHandler $handler): Response;
}
// system/Middleware/MiddlewareStack.php
namespace App\System\Middleware;
use App\System\Http\Request;
use App\System\Http\Response;
use App\System\Http\RequestHandler;
class MiddlewareStack implements RequestHandler
{
private $middlewares = [];
private $controller;
private $action;
private $params;
public function __construct(callable $controller, string $action, array $params = [])
{
$this->controller = $controller;
$this->action = $action;
$this->params = $params;
}
public function addMiddleware(MiddlewareInterface $middleware): self
{
$this->middlewares[] = $middleware;
return $this;
}
public function handle(Request $request): Response
{
if (empty($this->middlewares)) {
return $this->processController($request);
}
$middleware = array_shift($this->middlewares);
return $middleware->process($request, $this);
}
private function processController(Request $request): Response
{
$controller = $this->controller;
$action = $this->action;
$params = $this->params;
return $controller->$action(...$params);
}
}
// Penggunaan di bootstrap aplikasi
$app->run(function($request) use ($router) {
$route = $router->match($request->getMethod(), $request->getUri()->getPath());
if (!$route) {
return new Response('Not Found', 404);
}
$controller = new $route['controller']();
$action = $route['action'];
$params = $route['params'];
$stack = new MiddlewareStack($controller, $action, $params);
// Tambahkan global middleware
foreach ($app->getMiddlewares() as $middleware) {
$stack->addMiddleware($middleware);
}
// Tambahkan route middleware
foreach ($route['middleware'] as $middlewareClass) {
$stack->addMiddleware(new $middlewareClass());
}
// Proses request melalui middleware stack
return $stack->handle($request);
});
Middleware yang kompleks dapat memengaruhi performa aplikasi. Gunakan profiling tools untuk mengidentifikasi bottleneck.