Setiap request yang masuk ke aplikasi Laravel melewati perjalanan panjang sebelum controller akhirnya berjalan, dan perjalanan kembali ke pengguna juga tidak langsung. Middleware adalah lapisan-lapisan kode yang berdiri di tengah perjalanan itu: menyaring request sebelum diserahkan ke controller, dan menyentuh response sebelum dikirim keluar. Kebutuhan seperti memeriksa login, mencatat aktivitas, atau membatasi jumlah request bukan milik satu controller saja, melainkan kebutuhan lintas route. Dengan middleware, kita mengeluarkan logika lintas itu dari controller agar tidak diulang-ulang di banyak tempat.
Middleware sebagai Lapisan Bawang #
Bayangkan aplikasi sebagai inti bawang dan middleware sebagai kulit-kulit yang membungkusnya. Request menembus kulit dari luar ke dalam, controller memproses, lalu response menembus balik dari dalam ke luar. Middleware yang ditulis paling awal menjadi kulit terluar, sehingga kode before dan after middleware tersebut mengapit seluruh proses di dalamnya. Gambar berikut memperlihatkan bentuk umumnya:
Kita bisa membuktikan pola ini dengan dua middleware kecil bernama FirstLayer dan SecondLayer. Setiap lapisan menulis jejak (trace) sebelum dan sesudah memanggil $next($request), dan sebuah route menuliskan jejak controller di tengah:
// app/Http/Middleware/FirstLayer.php (potongan inti)
public function handle(Request $request, Closure $next): Response
{
TraceLog::add('Lapisan 1: sebelum');
$response = $next($request);
TraceLog::add('Lapisan 1: sesudah');
return $response;
}
// routes/web.php
Route::get('/lapisan', function () {
TraceLog::add('Controller: memproses');
return 'Isi controller';
})->middleware([FirstLayer::class, SecondLayer::class]);Feature test berikut memanggil route tersebut lalu mencetak seluruh jejak yang terkumpul:
public function test_urutan_lapisan_mengikuti_urutan_deklarasi(): void
{
TraceLog::$entries = [];
$response = $this->get('/lapisan');
echo 'trace: ', implode(' > ', TraceLog::$entries), PHP_EOL;
echo 'isi: ', $response->getContent(), PHP_EOL;
}Output yang Dihasilkan:
trace: Lapisan 1: sebelum > Lapisan 2: sebelum > Controller: memproses > Lapisan 2: sesudah > Lapisan 1: sesudah
isi: Isi controllerPerhatikan simetrinya: FirstLayer masuk paling awal dan keluar paling akhir. Middleware yang ditulis lebih dulu di daftar middleware() selalu membungkus semua middleware di dalamnya.
Logika Before dan After #
Kedua posisi middleware punya tugas berbeda. Logika before berjalan sebelum $next($request) dipanggil — tempat yang tepat untuk memvalidasi request, memeriksa session, atau menolak akses lebih awal. Jika kondisi tidak terpenuhi, middleware boleh mengembalikan response sendiri tanpa memanggil $next($request) sama sekali, sehingga controller tidak pernah dieksekusi. Logika after berjalan setelah $next($request) mengembalikan response — tempat untuk menambah header, mengubah isi, atau mencatat metrik sebelum response berangkat ke pengguna. Satu middleware boleh memakai keduanya sekaligus, seperti contoh FirstLayer di atas.
Pipeline: Mesin di Balik Lapisan #
Secara internal, Laravel membangun susunan bawang ini dengan komponen Pipeline. Pipeline menerima request, mengalirkannya melewati setiap middleware, lalu mengeksekusi inti di ujungnya. Potongan berikut meniru mekanisme itu dengan dua closure dan satu inti sederhana:
use Illuminate\Http\Request;
use Illuminate\Pipeline\Pipeline;
$request = Request::create('/contoh', 'GET');
$hasil = (new Pipeline($app))
->send($request)
->through([
function ($request, $next) {
echo "lapisan A: sebelum\n";
$response = $next($request);
echo "lapisan A: sesudah\n";
return $response;
},
function ($request, $next) {
echo "lapisan B: sebelum\n";
$response = $next($request);
echo "lapisan B: sesudah\n";
return $response;
},
])
->then(function ($request) {
echo "inti: controller berjalan\n";
return 'Respons dari controller';
});Output yang Dihasilkan:
lapisan A: sebelum
lapisan B: sebelum
inti: controller berjalan
lapisan B: sesudah
lapisan A: sesudah
hasil: 'Respons dari controller'Setiap middleware pada dasarnya adalah Closure($request, $next) yang memutuskan: meneruskan request ke lapisan berikutnya, atau menghentikannya. Kita akan jarang menyentuh Pipeline secara langsung, tetapi memahaminya menjelaskan mengapa urutan middleware berpengaruh besar. Detail posisi middleware dalam keseluruhan perjalanan request dibahas di dokumentasi lifecycle
.
Apa yang Cocok Dikerjakan Middleware #
Middleware paling tepat untuk kebutuhan yang berlaku umum bagi banyak route, bukan logika bisnis milik satu halaman:
| Kebutuhan | Contoh bawaan Laravel | Yang dilakukan |
|---|---|---|
| Autentikasi | auth, guest | Menahan tamu atau pengguna yang salah arah |
| Pembatasan laju | throttle | Menolak request yang terlalu sering dari satu IP |
| Berbagi resource lintas origin | HandleCors | Menambah header CORS pada response |
| Kebersihan input | TrimStrings, ConvertEmptyStringsToNull | Menormalkan data request masuk |
Konsepnya sudah jelas, tugas berikutnya adalah menulis middleware pertama kita sendiri — lengkap dengan logika before, after, dan feature test yang membuktikan keduanya berjalan. Panduan resminya tersedia di dokumentasi middleware .