ถ้าทุกหน้าในหลังบ้านต้องเช็คว่าล็อกอินแล้วหรือยัง เราคงไม่อยากเขียนเงื่อนไขเดิมไว้ต้น controller ทุกตัว Middleware คือที่สำหรับงานแบบนี้ เขียนไว้ที่เดียว แล้วบอกว่าใช้กับ route ไหน
Middleware คือด่านที่ request ต้องผ่าน
ลองนึกถึงคนเข้าตึกที่ต้องผ่าน รปภ. หน้าประตู แล้วแตะบัตรหน้าลิฟต์ก่อนถึงห้องที่จะไป ใครไม่มีบัตรก็จบตรงนั้น ไม่ได้ขึ้นไปถึงห้อง Middleware ก็ทำงานแบบเดียวกัน ทุกตัวได้เห็น request และเลือกได้ว่าจะปล่อยไปด่านถัดไปหรือตอบกลับเลย

Middleware แต่ละตัวทำงานได้ทั้งตอน request เข้ามาและตอน response ออกไป
ขาออก response จะผ่านด่านเดิมย้อนกลับมา งานที่ต้องแก้ของก่อนส่งออกจึงอยู่ใน middleware ได้เหมือนกัน เช่น AddQueuedCookiesToResponse ที่แนบ cookie ไปกับ response
Laravel แบ่ง middleware เป็นสามระดับ
| ระดับ | ทำงานกับ | ตัวอย่างที่ Laravel ใส่มาให้ |
|---|---|---|
| Global | ทุก request | TrustProxies, HandleCors, TrimStrings |
| Group | route ใน group นั้น เช่น web กับ api |
StartSession, PreventRequestForgery, SubstituteBindings |
| Route | เฉพาะ route ที่ระบุ | auth, verified, throttle |
ตัวที่เป็น group ทำให้หน้าเว็บใน routes/web.php ได้ session กับ cookie อัตโนมัติ ส่วนระดับ route คือที่เราเจอบ่อยสุดในงานประจำวัน
Route::get('/orders', [OrderController::class, 'index'])->middleware('auth');
เขียน middleware ของตัวเอง
สมมติเราอยากกันผู้ใช้ที่แอดมินระงับบัญชีไว้ไม่ให้เข้าระบบหลังร้าน
php artisan make:middleware EnsureUserIsActive
public function handle(Request $request, Closure $next): Response
{
if ($request->user()?->is_suspended) {
abort(403);
}
return $next($request);
}
$next($request) คือการปล่อยไปด่านถัดไป ถ้าไม่เรียกก็จะไม่ถึง controller โค้ดที่อยู่ก่อนบรรทัดนี้ทำงานขาเข้า ถ้าอยากทำอะไรขาออก ให้เก็บผลของ $next($request) ไว้ในตัวแปรก่อนแล้วค่อย return
จากนั้นตั้งชื่อสั้นไว้ใน bootstrap/app.php แล้วเรียกจาก route ได้เลย
->withMiddleware(function (Middleware $middleware) {
$middleware->alias(['active' => EnsureUserIsActive::class]);
})
Route::middleware(['auth', 'active'])->group(function () {
Route::get('/orders', [OrderController::class, 'index']);
});
รายละเอียดทั้งหมดอยู่ในเอกสาร Middleware ของ Laravel
ลำดับของ middleware มีผลกับงาน
Middleware ตัวหลังใช้ของที่ตัวก่อนเตรียมไว้ $request->session() ใช้ได้หลังจาก StartSession ทำงานแล้วเท่านั้น $request->ip() จะได้ IP ผู้ใช้จริงหลังจาก TrustProxies ทำงาน เราจึงต้องคิดด้วยว่าตัวของเราควรอยู่ตรงไหน
ถ้าต้องวางไว้ตรงกลาง stack ตั้งแต่ Laravel 13.40 มีinsertBefore() กับ insertAfter() ให้ใช้โดยไม่ต้องประกาศลำดับใหม่ทั้งชุด
การใช้งานจริงอาจเจอกรณีแบบนี้
Session store not set on request.middleware อ่าน session ทั้งที่ route อยู่นอกwebgroup หรือรันก่อนStartSessionเช่นเรียกในroutes/api.php- rate limit นับผู้ใช้หลายคนเป็นคนเดียว เว็บอยู่หลัง Cloudflare หรือ load balancer แล้ว
$request->ip()ได้ IP ของ proxy ต้องตั้ง trustProxies ให้ถูก - ตั้งภาษาใน middleware แล้วหน้าเว็บเปลี่ยน แต่ route model binding ยังใช้ภาษาเดิม เพราะ middleware รันหลัง
SubstituteBindings - แก้
bootstrap/app.phpแล้วไม่เห็นผล ลองดูลำดับจริงของ route ด้วยphp artisan route:list -vv






