Next.js / Middleware үндэс

Middleware үндэс

Хэрэглэгч хуудас руу хүсэлт илгээх үед Next.js сервер хариу өгөхөөс өмнө нэг зүйл тохиолдоно — middleware. Энэ бол хүсэлтийг таслан авч шалгах, өөрчлөх, эсвэл өөр хаяг руу илгээх боломж олгодог тусгай layer юм.

Middleware хэрхэн ажилладаг вэ?

код
Хэрэглэгч /profile руу орохыг оролдоно
             ↓
        Middleware ажиллана
             ↓
    Нэвтэрсэн үү? ──── Тийм ──→ /profile хуудас харуулна
             │
            Үгүй
             │
             ↓
        /login руу redirect хийнэ

Middleware нь middleware.ts файлд тодорхойлогдоно — энэ файл нь app/ директортой нэг түвшинд, төслийн root-д байрлана:

typescript
// middleware.ts  ← app/ фолдертой нэг түвшинд!
import { NextRequest, NextResponse } from "next/server";

export function middleware(request: NextRequest) {
  const { pathname } = request.nextUrl;

  console.log(`Хүсэлт: ${pathname}`);

  return NextResponse.next(); // хүсэлтийг үргэлжлүүлэн дамжуулна
}

Суpabase Auth-тай нэвтрэлт шалгах

Хамгийн түгээмэл хэрэглээ бол хамгаалагдсан хуудаснуудад нэвтрэлт шалгах:

typescript
// middleware.ts
import { NextRequest, NextResponse } from "next/server";
import { createServerClient } from "@supabase/ssr";

export async function middleware(request: NextRequest) {
  const response = NextResponse.next({
    request: { headers: request.headers },
  });

  const supabase = createServerClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
    {
      cookies: {
        getAll() {
          return request.cookies.getAll();
        },
        setAll(cookiesToSet) {
          cookiesToSet.forEach(({ name, value, options }) => {
            response.cookies.set(name, value, options);
          });
        },
      },
    },
  );

  const {
    data: { user },
  } = await supabase.auth.getUser();

  const { pathname } = request.nextUrl;

  // хамгаалагдсан хуудсуудад нэвтрэлт шаардана
  const protectedRoutes = ["/profile", "/courses"];
  const isProtected = protectedRoutes.some((route) =>
    pathname.startsWith(route),
  );

  if (isProtected && !user) {
    return NextResponse.redirect(new URL("/login", request.url));
  }

  // нэвтэрсэн хэрэглэгч login хуудсыг харахаас сэргийлэх
  if (pathname === "/login" && user) {
    return NextResponse.redirect(new URL("/courses", request.url));
  }

  return response;
}

matcher — middleware хэрхэн зааглах вэ?

Анхны тохиргоогоор middleware бүх хүсэлтэд ажиллана — статик файл, зураг зэрэгт ч. matcher ашиглан зөвхөн хэрэгтэй замуудад ажиллуулна:

typescript
// middleware.ts-н доод хэсэгт нэмнэ
export const config = {
  matcher: [
    /*
     * Дараах замуудыг алгасана:
     * - _next/static  (статик файл)
     * - _next/image   (зургийн оновчлол)
     * - favicon.ico
     * - public фолдерийн файлууд
     */
    "/((?!_next/static|_next/image|favicon.ico|public/).*)",
  ],
};

Эсвэл зөвхөн тодорхой замуудад ажиллуулах:

typescript
export const config = {
  matcher: ["/profile/:path*", "/courses/:path*", "/login"],
};

:path* гэдэг нь тухайн замын бүх дэд замуудыг хамарна гэсэн утгатай. /courses/:path* нь /courses, /courses/javascript, /courses/javascript/01-intro бүгдийг агуулна.

Дараагийн хичээлд:

Cookie болон Header ашиглан хүсэлтийн мэдээлэл уших, тохируулах аргыг судална. Middleware болон Route Handler дотор хэрхэн ашигладгийг практик жишээгээр ойлгоно.