Laravel Middleware คืออะไร

Middleware คือด่านที่ request ต้องผ่านก่อนถึง controller และ response ต้องผ่านอีกครั้งตอนออก ใช้กับงานที่ซ้ำทุกหน้าอย่างเช็คการล็อกอิน เปิด session หรือตั้งภาษา โดย Laravel จัดเป็นสามระดับ ทั้งทุก request, ตาม group และเฉพาะ route

เผยแพร่
เวลาอ่าน
2 นาที
แท็ก
#HTTP#Laravel
ในโพสต์นี้ 5 หัวข้อ
  1. Middleware คือด่านที่ request ต้องผ่าน
  2. Laravel แบ่ง middleware เป็นสามระดับ
  3. เขียน middleware ของตัวเอง
  4. ลำดับของ middleware มีผลกับงาน
  5. การใช้งานจริงอาจเจอกรณีแบบนี้

ถ้าทุกหน้าในหลังบ้านต้องเช็คว่าล็อกอินแล้วหรือยัง เราคงไม่อยากเขียนเงื่อนไขเดิมไว้ต้น controller ทุกตัว Middleware คือที่สำหรับงานแบบนี้ เขียนไว้ที่เดียว แล้วบอกว่าใช้กับ route ไหน

Middleware คือด่านที่ request ต้องผ่าน

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

request ผ่าน middleware ทีละด่าน

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

รายละเอียดทั้งหมดอยู่ในเอกสาร 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 อยู่นอก web group หรือรันก่อน 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

อ่านต่อ

ถูกอ้างถึงใน

ล่าสุด

ดูทั้งหมด →