๐ก๏ธ Next.js 13์ฅ: Middleware & Edge Runtime โ ์์ฒญ์ ๊ฐ๋ก์ฑ๋ Edge ๊ฒฝ๋น์
๐ ๊ฐ์
Middleware์ Edge Runtime์ผ๋ก ์์ฒญ์ ๊ฐ๋ก์ฑ๊ณ ์ธ์ฆ ๋ฆฌ๋ค์ด๋ ํธ, A/B ํ ์คํธ๋ฅผ ๊ตฌํํฉ๋๋ค.
๐ ๋ชฉ์ฐจ
- ๐ ์ด ๋ฌธ์๋ฅผ ์ฝ๊ธฐ ์ ์
- ๐ค ์ ์์์ผ ํ๋๊ฐ
- ๐๏ธ ๋น์ ๋ก ๋จผ์ ์ดํดํ๊ธฐ
- ๐งฉ middleware.ts ๊ธฐ๋ณธ ๊ตฌ์กฐ โ ๋ชจ๋ ์์ฒญ์ ์ฒซ ๊ด๋ฌธ ๐ข
- ๐ ์ธ์ฆ ๋ฆฌ๋๋ ํธ ํจํด โ ๋ก๊ทธ์ธ ์ ํ ์ฌ๋ ์ฐจ๋จํ๊ธฐ ๐ก
- ๐ Edge Runtime์ด๋ ๋ฌด์์ธ๊ฐ ๐ก
- ๐ ๋ณด์ ํค๋ ์ค์ โ CSP์ HSTS ๐ด
- ๐ฅ ์๋ฌ ํด๊ฒฐ ์นดํ๋ก๊ทธ
- ๐ ์ด๋ฒ์ ๋ฐฐ์ด ๋ด์ฉ ์ด์ ๋ฆฌ
- ๐ ๋ง๋ฌด๋ฆฌ ํด์ฆ
- ๐ ๋ ์์๋ณด๊ธฐ
๐ ์ด ๋ฌธ์๋ฅผ ์ฝ๊ธฐ ์ ์
โฑ๏ธ ์์ ์ฝ๊ธฐ ์๊ฐ: 15๋ถ (์ ์ฒด) / ํต์ฌ ํํธ๋ง: 7๋ถ
๐บ๏ธ ์ด ๋ฌธ์์ ๋ฐฐ๊ฒฝ ์ธ๊ณ๊ด: '์์๋ค ์ปค๋ฎค๋ํฐ'
- ์์ฒ (์ ์
): "๋ก๊ทธ์ธ ์ ํ ์ฌ์ฉ์๊ฐ
/dashboardํ์ด์ง์ ์ ๊ทผํ๋ ค ํ๋ฉด/login์ผ๋ก ๋ณด๋ด์ผ ํ๋๋ฐ... ๊ฐ ํ์ด์ง ์ปดํฌ๋ํธ ์๋จ๋ง๋ค ์ธ์ ์ฒดํฌ ์ฝ๋๋ฅผ ๋ณต๋ถํด์ผ ํ๋์? ํ์ด์ง๊ฐ 100๊ฐ๋ฉด 100๊ตฐ๋ฐ ๋ค ์จ์ผ ํด์?" - ์ํธ(๋ฆฌ๋): "์ ๋ ๊ทธ๋ฌ๋ฉด ์ ๋์ฃ !
middleware.tsํ์ผ ํ๋๋ฅผ ํ๋ก์ ํธ ๋ฃจํธ์ ๋๋ฉด ๋ผ์. ๋ชจ๋ ์์ฒญ์ด ํ์ด์ง์ ๋์ฐฉํ๊ธฐ ์ ์ ์ด ํ์ผ์ ๋ฌด์กฐ๊ฑด ๊ฑฐ์น๊ฑฐ๋ ์. ๊ฒฝ๋น์์ฒ๋ผ ๋ฑ ํ ๊ณณ์์ ๋ชจ๋ ์ถ์ ์ ํต์ ํ๋ ๊ฑฐ์์."
๐บ๏ธ ์ด ๋ฌธ์์ ํ๋ฆ
Middleware ์คํ ์์น โ ์ธ์ฆ ๋ฆฌ๋๋ ํธ โ Edge Runtime ๊ฐ๋
โ ๋ณด์ ํค๋ ์ค์
๐ฏ ์ด ๋ฌธ์๋ฅผ ๋ค ์ฝ์ผ๋ฉด ํ ์ ์๋ ๊ฒ
-
middleware.ts๋ก ๋ก๊ทธ์ธ ์ฌ๋ถ์ ๋ฐ๋ผ ํ์ด์ง ์ ๊ทผ์ ์ ์ดํ ์ ์๋ค -
matcher๋ก Middleware๊ฐ ์คํ๋ ๊ฒฝ๋ก๋ฅผ ์ ๋ฐํ๊ฒ ์ ์ดํ ์ ์๋ค - Edge Runtime์ด Node.js์ ์ด๋ป๊ฒ ๋ค๋ฅธ์ง ์ค๋ช ํ ์ ์๋ค
๐ค ์ ์์์ผ ํ๋๊ฐ
์๋น์ค๋ฅผ ๋ง๋ค๋ค ๋ณด๋ฉด ๋ฐ๋์ ์ด๋ฐ ์๊ตฌ์ฌํญ์ด ์๊ฒจ:
- ๋ก๊ทธ์ธํ ์ฌ์ฉ์๋ง
/dashboard,/my,/settings์ ๊ทผ ๊ฐ๋ฅ - ํน์ ๊ตญ๊ฐ(์ง์ญ)์ ๋ฐ๋ผ ๋ค๋ฅธ ํ์ด์ง๋ก ๋ผ์ฐํ (A/B ํ ์คํธ, ๋ค๊ตญ์ด)
- ๋ชจ๋ ์๋ต์ ๋ณด์ ํค๋(
X-Frame-Options,CSP) ์๋ ์ถ๊ฐ - ํน์ ๋ด ๋๋ IP ์ฐจ๋จ
์ด๊ฑธ ๊ฐ ํ์ด์ง๋ง๋ค ๊ตฌํํ๋ฉด ์ฝ๋ ์ค๋ณต, ๋น ๋จ๋ฆฌ๋ ํ์ด์ง ๋ฐ์, ์ ์ง๋ณด์ ๋๋งฅ์ด ํผ์ณ์ ธ.
Middleware๋ ๋ชจ๋ ์์ฒญ์ ๊ณตํต ๊ด๋ฌธ์ด์ผ. CDN ์ฃ์ง ๋ ธ๋์์ ์คํ๋๊ธฐ ๋๋ฌธ์ ์๋ฒ๋ DB์ ๋๋ฌํ๊ธฐ๋ ์ ์, ์ฌ์ง์ด Next.js ์ฑ ์์ฒด์ ์์ฒญ์ด ๋ฟ๊ธฐ ์ ์ ๋จผ์ ์คํ๋ผ. ์ด๊ฒ ํต์ฌ์ด์ผ.
๐๏ธ ๋น์ ๋ก ๋จผ์ ์ดํดํ๊ธฐ
๐ง 5์ด์๊ฒ ์ค๋ช ํ๋ค๋ฉด?
์ํํธ ์ ๊ตฌ์ ๊ฒฝ๋น์์ด ์์ด. ๋๊ฐ ๋ค์ด์ค๋ ๋จผ์ ๊ฒฝ๋น์์ ๋ง๋์ผ ํด.
"์ ์ฃผ๋ฏผ ์นด๋ ์์ด์?" โ ์์ผ๋ฉด ๋ชป ๋ค์ด๊ฐ๊ฒ ๋ง์.
"๋ช ๋ ๊ฐ์ธ์?" โ 1๋์ ์ผ์ชฝ, 2๋์ ์ค๋ฅธ์ชฝ์ผ๋ก ์๋ดํด์ค.Middleware๊ฐ ๊ทธ ๊ฒฝ๋น์์ด์ผ. ๋ชจ๋ ์์ฒญ์ด ์ค์ ํ์ด์ง(์ํํธ ๊ฐ ์ธ๋)์ ๋ฟ๊ธฐ ์ ์ ๋ฐ๋์ ๊ฒฝ๋น์์ ๊ฑฐ์ณ์ผ ํด.
Middleware์ ์คํ ์์น:
์ฌ์ฉ์ ๋ธ๋ผ์ฐ์ ์์ฒญ
โ
๐ก๏ธ middleware.ts (Edge์์ ์คํ, ๊ฐ์ฅ ๋จผ์ !)
โ
Next.js ์ฑ ์๋ฒ
โ
layout.tsx โ page.tsx
๐งฉ middleware.ts ๊ธฐ๋ณธ ๊ตฌ์กฐ โ ๋ชจ๋ ์์ฒญ์ ์ฒซ ๊ด๋ฌธ ๐ข
๐ฏ ์ด ์น์ ์ ์ฝ๊ณ ๋๋ฉด:
middleware.tsํ์ผ์ ํ๋ก์ ํธ ๋ฃจํธ์ ๋ง๋ค์ด ๋ชจ๋ ์์ฒญ์ ๊ฐ๋ก์ฑ ์ ์๋คNextResponse.redirect()์NextResponse.next()์ ์ฐจ์ด๋ฅผ ์๋คmatcher๋ก Middleware ์คํ ๊ฒฝ๋ก๋ฅผ ์ ์ดํ ์ ์๋ค
// middleware.ts (ํ๋ก์ ํธ ๋ฃจํธ โ app ํด๋์ ๊ฐ์ ๋ ๋ฒจ)
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
const { pathname } = request.nextUrl
console.log(`[Middleware] ์์ฒญ ๊ฒฝ๋ก: ${pathname}`)
// ํน์ ์กฐ๊ฑด์์ ๋ฆฌ๋๋ ํธ
if (pathname === '/old-posts') {
// NextResponse.redirect: ๋ค๋ฅธ URL๋ก ์๊ตฌ ๋ณด๋ด๊ธฐ
return NextResponse.redirect(new URL('/posts', request.url))
}
// ์์ฒญ ํค๋์ ์ ๋ณด ์ถ๊ฐ (ํ์ด์ง ์ปดํฌ๋ํธ์์ ์ฝ์ ์ ์์)
const requestHeaders = new Headers(request.headers)
requestHeaders.set('x-pathname', pathname)
// NextResponse.next(): "ํต๊ณผ, ๋ค์์ผ๋ก ์งํํด"
return NextResponse.next({
request: { headers: requestHeaders },
})
}
// โ๏ธ matcher: Middleware๋ฅผ ์คํํ ๊ฒฝ๋ก ํจํด ์ค์
export const config = {
matcher: [
// ์๋ ๊ฒฝ๋ก๋ค์ ์ ์ธํ ๋ชจ๋ ๊ฒฝ๋ก์์ ์คํ
// ์ด๋ฏธ์ง, ์ ์ ํ์ผ, API ๋ฑ์ ๋ณดํต ์ ์ธํ๋ ๊ฒ ์ฑ๋ฅ์ ์ข์
'/((?!_next/static|_next/image|favicon.ico|api/webhooks).*)',
],
}matcher ํจํด ์์ฑ๋ฒ:
| ํจํด | ์๋ฏธ |
|---|---|
'/dashboard' | /dashboard ์ ํํ ์ผ์น |
'/dashboard/:path*' | /dashboard ํ์ ๋ชจ๋ ๊ฒฝ๋ก |
| `'/((?!api | _next).*)' ` |
['/dashboard/:path*', '/my/:path*'] | ๋ฐฐ์ด๋ก ์ฌ๋ฌ ๊ฒฝ๋ก ์ง์ |
๐ก ํ ์ค๋ก ๊ธฐ์ตํ๊ธฐ
middleware.ts๋ ์ํํธ ๊ฒฝ๋น์.matcher๋ ๊ฒฝ๋น์ ๊ทผ๋ฌด ๊ตฌ์ญ ์ง๋์ผ. ์ง๋์ ์๋ ๊ณณ์ ๊ทธ๋ฅ ํต๊ณผ์์ผ.
๐ ์ธ์ฆ ๋ฆฌ๋๋ ํธ ํจํด โ ๋ก๊ทธ์ธ ์ ํ ์ฌ๋ ์ฐจ๋จํ๊ธฐ ๐ก
๐ฏ ์ด ์น์ ์ ์ฝ๊ณ ๋๋ฉด:
- ์ฟ ํค์ ์ธ์ ํ ํฐ์ ์ฝ์ด ๋ก๊ทธ์ธ ์ฌ๋ถ๋ฅผ ํ๋จํ ์ ์๋ค
- ๋ก๊ทธ์ธ ์ ํ ์ฌ์ฉ์๋ฅผ
/login์ผ๋ก ๋ฆฌ๋๋ ํธํ๋ ํจํด์ ๊ตฌํํ ์ ์๋ค
๐ค ์ ๊น, ๋จผ์ ์๊ฐํด๋ด
์ธ์ ํ ํฐ์ ์ฟ ํค์ ์์ด. Middleware์์ ์ฟ ํค๋ฅผ ์ฝ์ด์ ์ ํจํ ์ธ์ ์ธ์ง ์ด๋ป๊ฒ ํ์ธํ ์ ์์๊น?
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
// ๋ก๊ทธ์ธ ์์ด ์ ๊ทผ ๊ฐ๋ฅํ ๊ณต๊ฐ ๊ฒฝ๋ก ๋ชฉ๋ก
const PUBLIC_PATHS = ['/', '/login', '/signup', '/posts']
export function middleware(request: NextRequest) {
const { pathname } = request.nextUrl
// ๊ณต๊ฐ ๊ฒฝ๋ก๋ ๋ฐ๋ก ํต๊ณผ
const isPublic = PUBLIC_PATHS.some(
(path) => pathname === path || pathname.startsWith(`${path}/`)
)
if (isPublic) return NextResponse.next()
// ์ฟ ํค์์ ์ธ์
ํ ํฐ ์ฝ๊ธฐ
const sessionToken = request.cookies.get('session')?.value
// ์ธ์
์ด ์์ผ๋ฉด ๋ก๊ทธ์ธ ํ์ด์ง๋ก ๋ฆฌ๋๋ ํธ
if (!sessionToken) {
const loginUrl = new URL('/login', request.url)
// ๋ก๊ทธ์ธ ํ ์๋ ๊ฐ๋ ค๋ ํ์ด์ง๋ก ๋์์ค๊ธฐ ์ํด callbackUrl ํ๋ผ๋ฏธํฐ ์ถ๊ฐ
loginUrl.searchParams.set('callbackUrl', pathname)
return NextResponse.redirect(loginUrl)
}
// โ ๏ธ ์ฃผ์: Middleware๋ Edge Runtime์์ ๋์๊ฐ
// DB ์กฐํ๋ ๋ฌด๊ฑฐ์ด JWT ๊ฒ์ฆ์ ์ฌ๊ธฐ์ ํ๋ฉด ์ ๋ผ
// ๊ฐ๋จํ ํ ํฐ ์กด์ฌ ์ฌ๋ถ ํ์ธ๋ง ํ๊ณ , ์ค์ ๊ฒ์ฆ์ ํ์ด์ง/API์์ ํด
return NextResponse.next()
}
export const config = {
// ์ ์ ํ์ผ, ์ด๋ฏธ์ง, API๋ ์ ์ธ
matcher: ['/((?!_next/static|_next/image|favicon.ico|api).*)'],
}์ด ํจํด์ ํ๊ณ์ ์ฌ๋ฐ๋ฅธ ์ญํ ๋ถ๋ฆฌ:
Middleware (Edge) โ "ํ ํฐ์ด ์๋๊ฐ?" ๋ง ํ์ธ (๋น ๋ฅธ 1์ฐจ ์ฒดํฌ)
โ ํต๊ณผ
ํ์ด์ง / Server Action โ "ํ ํฐ์ด ์ ํจํ๊ฐ? ๊ถํ์ด ์๋๊ฐ?" ์ฌ์ธต ๊ฒ์ฆ (๋๋ฆฌ์ง๋ง ์ ํ)
โ ๏ธ ์ฃผ์: Middleware์์ DB ์ฟผ๋ฆฌ๋ ๋ณต์กํ ์ํธํ ์ฐ์ฐ์ ํ๋ฉด ์ ๋ผ. Edge Runtime์ Node.js API ์ผ๋ถ๊ฐ ์ ํ๋์ด ์๊ณ , ๋ชจ๋ ์์ฒญ๋ง๋ค ์คํ๋๋ฏ๋ก ์ฑ๋ฅ์ ์ง๊ฒฐ๋ผ.
๐ ์ฐ๊ฒฐ ๊ณ ๋ฆฌ
์ธ์ ๊ฒ์ฆ์ ์ฌ์ธต ํจํด (DAL,verifySession())์ ์ฌํ 7์ฅ Authentication Architecture์์ ์์ธํ ๋ค๋ค. ์ง๊ธ์ Middleware์ 1์ฐจ ๊ด๋ฌธ ์ญํ ๋ง ํ์ ํ๋ฉด ์ถฉ๋ถํด.
๐ Edge Runtime์ด๋ ๋ฌด์์ธ๊ฐ ๐ก
๐ฏ ์ด ์น์ ์ ์ฝ๊ณ ๋๋ฉด:
- Edge Runtime๊ณผ Node.js Runtime์ ์ฐจ์ด๋ฅผ ์ค๋ช ํ ์ ์๋ค
- Middleware์์ ์ฌ์ฉํ ์ ์๋ Node.js API๊ฐ ๋ฌด์์ธ์ง ์๊ณ ๋์์ ์ฐพ์ ์ ์๋ค
๐ ์ฉ์ด: Edge Runtime โ ์ฌ์ฉ์์๊ฒ ๊ฐ์ฅ ๊ฐ๊น์ด CDN ์ฃ์ง ์๋ฒ์์ ์ฝ๋๋ฅผ ์คํํ๋ ํ๊ฒฝ์ด์ผ. ์ผ๋ฐ ์๋ฒ(Origin)๊น์ง ์์ฒญ์ด ๋ฟ์ง ์์๋ ๋๋๊น ๋ ์ดํด์๊ฐ ํจ์ฌ ๋ฎ์.
์ผ๋ฐ Node.js ์๋ฒ
์ฌ์ฉ์(์์ธ) โ ์๋ฒ(๋ฏธ๊ตญ) โ ์๋ต ๋ฐํ [๋ ์ดํด์: 200ms+]
Edge Runtime
์ฌ์ฉ์(์์ธ) โ ์์ธ ์ฃ์ง ๋
ธ๋ โ ์๋ต ๋ฐํ [๋ ์ดํด์: 10ms ์ดํ]
Edge Runtime์์ ์ฌ์ฉํ ์ ์๋ ๊ฒ๋ค:
| ์ฌ์ฉ ๋ถ๊ฐ | ์ด์ | ๋์ |
|---|---|---|
fs (ํ์ผ ์์คํ
) | Edge ํ๊ฒฝ์ ์๋ฒ ํ์ผ ์์คํ ์์ | S3 ๋ฑ ์ธ๋ถ ์คํ ๋ฆฌ์ง ์ฌ์ฉ |
| ๋๋ถ๋ถ์ npm ํจํค์ง | Node.js ์ ์ฉ API ์์กด | Edge ํธํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํ์ธ |
๋ฌด๊ฑฐ์ด ์ํธํ (bcrypt) | CPU ์ง์ค ์์ ๊ธ์ง | jose ๊ฐ์ ๊ฐ๋ฒผ์ด ๋์ ์ฌ์ฉ |
| Prisma, Drizzle ๋ฑ DB ํด๋ผ์ด์ธํธ | TCP ์์ผ ์์กด | HTTP ๊ธฐ๋ฐ DB ๋๋ ํ์ด์ง์์ ์ฒ๋ฆฌ |
// โ Middleware์์ ์ฐ๋ฉด ์ ๋๋ ํจํด
import bcrypt from 'bcrypt' // Node.js ์ ์ฉ โ Edge์์ ์๋ฌ!
import { PrismaClient } from '@prisma/client' // TCP ์์ผ โ Edge์์ ์๋ฌ!
// โ
Middleware์์ ์ธ ์ ์๋ ํจํด
import { jwtVerify } from 'jose' // Web Crypto API ๊ธฐ๋ฐ โ Edge ํธํ!
const token = request.cookies.get('session')?.value // Web API โ Edge ํธํ!๐ก ํ ์ค๋ก ๊ธฐ์ตํ๊ธฐ
Edge Runtime์ "์ด๊ฒฝ๋ ์คํ ํ๊ฒฝ"์ด์ผ. ๋น ๋ฅธ ๋์ Node.js์ ๋ฌด๊ฑฐ์ด ๊ธฐ๋ฅ์ ๋ชป ์จ. Middleware๋ ์ฌ๊ธฐ์ ๋์๊ฐ๋ ๊ฐ๋ณ๊ฒ ์จ์ผ ํด.
๐ ๋ณด์ ํค๋ ์ค์ โ CSP์ HSTS ๐ด
๐ฏ ์ด ์น์ ์ ์ฝ๊ณ ๋๋ฉด:
- Middleware์์ ๋ชจ๋ ์๋ต์ ๋ณด์ ํค๋๋ฅผ ์๋์ผ๋ก ์ถ๊ฐํ๋ ํจํด์ ๊ตฌํํ ์ ์๋ค
Middleware๋ ๋ชจ๋ ์๋ต์ ํค๋๋ฅผ ์ถ๊ฐํ๊ธฐ์ ์๋ฒฝํ ์์น์ผ.
// middleware.ts โ ๋ณด์ ํค๋ ์ค์ ํจํด
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
const response = NextResponse.next()
// XSS ๋ฐฉ์ด: ๋ธ๋ผ์ฐ์ ๊ฐ Content-Type์ ๋ฌด์ํ์ง ๋ชปํ๊ฒ ๊ฐ์
response.headers.set('X-Content-Type-Options', 'nosniff')
// ํด๋ฆญ์ฌํน ๋ฐฉ์ด: ๋ค๋ฅธ ์ฌ์ดํธ์ iframe์์ ์ฐ๋ฆฌ ํ์ด์ง ์๋ฒ ๋ ๊ธ์ง
response.headers.set('X-Frame-Options', 'DENY')
// HTTPS ๊ฐ์ : 1๋
๊ฐ HTTPS๋ง ํ์ฉ (HSTS)
response.headers.set(
'Strict-Transport-Security',
'max-age=31536000; includeSubDomains'
)
// CSP: ์คํฌ๋ฆฝํธยท์ด๋ฏธ์งยทํฐํธ ์์ค ํ์ดํธ๋ฆฌ์คํธ
response.headers.set(
'Content-Security-Policy',
[
"default-src 'self'",
"script-src 'self' 'unsafe-inline'", // Next.js inline script ํ์ฉ
"img-src 'self' data: https:",
"font-src 'self' https://fonts.gstatic.com",
].join('; ')
)
return response
}๐ฅ ์๋ฌ ํด๊ฒฐ ์นดํ๋ก๊ทธ
โ require() of ES modules is not supported
์ธ์ ๋์ค๋๊ฐ?
Error: require() of ES Module ... not supported.
์์ธ: Middleware(Edge Runtime)์์ CommonJS ๋ชจ๋์ importํ์ ๋. bcrypt, jsonwebtoken ๊ฐ์ ํจํค์ง๊ฐ ์ฃผ๋ฒ.
ํด๊ฒฐ์ฑ :
// โ ์๋ฌ ๋ฐ์
import jwt from 'jsonwebtoken' // CJS ํจํค์ง
// โ
Edge ํธํ ๋์
import { jwtVerify, SignJWT } from 'jose' // Web Crypto API ๊ธฐ๋ฐโ Middleware๊ฐ ์ ์ ํ์ผ ์์ฒญ์๋ ์คํ๋์ด ๋๋ ค์ง
์์ธ: matcher๋ฅผ ์ค์ ํ์ง ์์ CSS, JS, ์ด๋ฏธ์ง ํ์ผ ์์ฒญ์๋ Middleware๊ฐ ์คํ๋จ.
ํด๊ฒฐ์ฑ :
export const config = {
matcher: [
// _next ํ์ ์ ์ ํ์ผ๊ณผ favicon์ ์ ์ธ
'/((?!_next/static|_next/image|favicon.ico).*)',
],
}๐ ์ด๋ฒ์ ๋ฐฐ์ด ๋ด์ฉ ์ด์ ๋ฆฌ
๐ ํต์ฌ ๋ช ๋ น ํจํด
| ์ํฉ | ์ฝ๋ |
|---|---|
| ๋ค๋ฅธ URL๋ก ๋ณด๋ด๊ธฐ | NextResponse.redirect(new URL('/login', request.url)) |
| ๊ทธ๋ฅ ํต๊ณผ | NextResponse.next() |
| ์๋ต ํค๋ ์ถ๊ฐ | response.headers.set('X-Frame-Options', 'DENY') |
| ์ฟ ํค ์ฝ๊ธฐ | request.cookies.get('session')?.value |
| URL ๊ฒฝ๋ก ์ฝ๊ธฐ | request.nextUrl.pathname |
โ ๏ธ ์ ๋ ํ์ง ๋ง ๊ฒ
| ์ํฉ | โ ๋์ ์ | โ ์ข์ ์ |
|---|---|---|
| DB ์กฐํ | Middleware์์ Prisma ์ฌ์ฉ | ํ์ด์ง/API Route์์ ์ฒ๋ฆฌ |
| ๋ฌด๊ฑฐ์ด ์ํธํ | bcrypt.compare() in middleware | jose์ jwtVerify() |
| matcher ์์ | ๋ชจ๋ ๊ฒฝ๋ก์์ ์คํ | ์ ์ ํ์ผ ๊ฒฝ๋ก ์ ์ธ |
๐ ๋ง๋ฌด๋ฆฌ ํด์ฆ
Q1. Middleware๋ ์์ฒญ ํ๋ฆ์์ ์ธ์ ์คํ๋ ๊น?
โ ์ ๋ต: ๋ผ์ฐํธ ๋ก์ง์ ๋๋ฌํ๊ธฐ ์ Edge์์ ๋จผ์ ์คํ๋๋ค.
๐ก ์์ธ ํด์ค: ๊ทธ๋์ ๋ฆฌ๋ค์ด๋ ํธ, ๊ฐ๋จํ ์ธ์ฆ ์กด์ฌ ํ์ธ, ์ง์ญ/์ธ์ด ๋ถ๊ธฐ์ฒ๋ผ ๋น ๋ฅธ ํ๋จ์ ์ ํฉํ๋ค.
Q2. Middleware์ ๋ฌด๊ฑฐ์ด DB ๊ถํ ๊ฒ์ฌ๋ฅผ ๋ฃ์ผ๋ฉด ์ ์ํํ ๊น?
โ ์ ๋ต: Edge Runtime ์ ์ฝ๊ณผ ์ฑ๋ฅ ๋น์ฉ ๋๋ฌธ์ ๋ชจ๋ ์์ฒญ์ ๋ณ๋ชฉ์ด ๋ ์ ์๋ค.
๐ก ์์ธ ํด์ค: Middleware๋ ๋๊ฒ ์คํ๋๋ค. ์ ๋ฐํ ๊ถํ๊ณผ ์์ ๊ถ ๊ฒ์ฌ๋ ์๋ฒ์ DAL์ด๋ Route Handler/Server Action์์ ๋ค์ ํ์ธํ๋ ํธ์ด ์์ ํ๋ค.
Q3. ์์ฒ ์ด์ ํ ์คํธ ํ์: /admin ์ ๊ทผ์ ๋ง์์ผ ํ๋ค. Middleware๋ง์ผ๋ก ์ถฉ๋ถํ ๊น?
โ ์ ๋ต: ์๋๋ค. Middleware๋ 1์ฐจ๋ก ๊ฑธ๋ฌ๋ด๊ณ , ์ค์ ๋ฐ์ดํฐ ๋ณ๊ฒฝ ์ง์ ์์ role์ ๋ค์ ํ์ธํด์ผ ํ๋ค.
๐ก ์์ธ ํด์ค: URL ์ ๊ทผ ์ฐจ๋จ์ ์ข์ ์์์ด์ง๋ง ์ง์ ์์ฒญ์ด๋ ๋ด๋ถ ํธ์ถ๊น์ง ๋ง์ง๋ ๋ชปํ๋ค. ๋ณด์์ ์ฌ๋ฌ ๊ฒฝ๊ณ๊ฐ ๊ฒน์ณ์ผ ํ๋ค.
๐ฃ ์์ฒ ์ด์ ํด๊ทผ ์ผ๊ธฐ
์ค๋์ Middleware๋ฅผ ๋ชจ๋ ๋ณด์ ๋ก์ง์ ๋ฃ๋ ์ฅ์๋ก ์ฐฉ๊ฐํ์ง ์๊ฒ ๋๋ค.
๐ก "Edge์์๋ ๋น ๋ฅด๊ฒ ๊ฑฐ๋ฅด๊ณ , ์๋ฒ์์๋ ์ ํํ๊ฒ ๊ฒ์ฆํ๋ค."
์์ผ๋ก matcher ๋ฒ์์ DAL ๊ถํ ๊ฒ์ฌ๋ฅผ ํ ์์ผ๋ก ๋ฆฌ๋ทฐํ๊ฒ ๋ค.
๐ ๋ ์์๋ณด๊ธฐ
- Next.js ๊ณต์ ๋ฌธ์ โ Middleware
- Edge Runtime ์ง์ API ๋ชฉ๋ก
- jose ๋ผ์ด๋ธ๋ฌ๋ฆฌ (Edge ํธํ JWT)