Middleware และ Request Lifecycle
ไอเดียในหนึ่งประโยค
หัวข้อที่มีชื่อว่า “ไอเดียในหนึ่งประโยค”ไฟล์ middleware.ts ที่ root ของโปรเจกต์จะรันก่อน request จะเสร็จ บนทุก route ที่ match ทำให้เรา redirect, rewrite หรือ set header กับ cookie ได้ก่อนที่ Next.js จะ render อะไรออกมา
Where middleware sits in the request lifecycle
หัวข้อที่มีชื่อว่า “Where middleware sits in the request lifecycle”middleware ดัก request หลังจาก request มาถึงแต่ก่อน route จะถูก resolve เรา return NextResponse เพื่อ redirect, rewrite หรือปล่อยผ่านด้วย NextResponse.next()
// middleware.ts — runs BEFORE the request completes, on every matching routeimport { NextResponse } from 'next/server'import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) { // Lightweight auth gate: redirect logged-out users away from /dashboard const isLoggedIn = request.cookies.has('session') if (request.nextUrl.pathname.startsWith('/dashboard') && !isLoggedIn) { return NextResponse.redirect(new URL('/login', request.url)) }
// Otherwise continue, and set a header on the way through const response = NextResponse.next() response.headers.set('x-request-time', Date.now().toString()) return response}Scope it with matcher
หัวข้อที่มีชื่อว่า “Scope it with matcher”ถ้าไม่มี matcher middleware จะรันทุก request รวมถึง static asset ด้วย เราจึงควร scope ให้รันเฉพาะจุดที่ต้องการ config matcher รับ path pattern และ exclude ส่วน internal ได้
// middleware.ts — scope which routes run middlewareexport const config = { matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],}Redirects, rewrites, and the Edge runtime
หัวข้อที่มีชื่อว่า “Redirects, rewrites, and the Edge runtime”ใช้ middleware สำหรับ redirect, rewrite (URL เดิมแต่เสิร์ฟ content ต่างกัน) และ set header หรือ cookie การ rewrite เสิร์ฟ content คนละแบบโดยไม่เปลี่ยน URL บน browser เหมาะกับ A/B test หรือ geo routing
// A/B or geo rewrite — same URL, different content servedimport { NextResponse } from 'next/server'import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) { const country = request.headers.get('x-vercel-ip-country') ?? 'us' return NextResponse.rewrite(new URL(`/${country}${request.nextUrl.pathname}`, request.url))}middleware รันบน Edge runtime เป็น default และอยู่หน้าทุก request ที่ match เพราะฉะนั้นต้องเร็ว ไม่ยิง database ไม่คำนวณหนัก ไม่ใช้ dependency ใหญ่ ตัดสินใจเบา ๆ ตรงนี้แล้วโยนงานจริงไปที่ route
graph LR A["Incoming request"] --> B["middleware.ts (Edge)"] B -->|redirect| C["NextResponse.redirect"] B -->|rewrite| D["NextResponse.rewrite"] B -->|next| E["Route handler / page"]