SvelteKit Hooks — 요청 파이프라인 제어하기
Express의 미들웨어처럼, SvelteKit의 Hooks는 모든 요청이 지나가는 관문입니다.
개념 정의
Hooks 는 SvelteKit의 요청 처리 파이프라인을 커스터마이징하는 함수입니다. src/hooks.server.js에서 서버 측 훅을, src/hooks.client.js에서 클라이언트 측 훅을 정의합니다.
handle — 모든 요청 가로채기
// src/hooks.server.js
// 모든 서버 요청이 이 함수를 통과합니다
export async function handle({ event, resolve }) {
// 1. 요청 전 처리
const sessionId = event.cookies.get('session');
if (sessionId) {
const user = await getUserFromSession(sessionId);
event.locals.user = user;
}
// 2. 요청 처리 (라우트 핸들러 실행)
const response = await resolve(event);
// 3. 응답 후 처리
response.headers.set('X-Custom-Header', 'value');
return response;
}
인증 가드 패턴
// src/hooks.server.js
import { redirect } from '@sveltejs/kit';
const protectedRoutes = ['/dashboard', '/settings', '/profile'];
export async function handle({ event, resolve }) {
// 세션 확인
const session = event.cookies.get('session');
event.locals.user = session ? await verifySession(session) : null;
// 보호된 라우트 접근 제어
const isProtected = protectedRoutes.some(
route => event.url.pathname.startsWith(route)
);
if (isProtected && !event.locals.user) {
redirect(302, `/login?redirect=${event.url.pathname}`);
}
return resolve(event);
}
여러 handle 함수 조합
// src/hooks.server.js
import { sequence } from '@sveltejs/kit/hooks';
// 인증 훅
async function auth({ event, resolve }) {
const session = event.cookies.get('session');
event.locals.user = session ? await verifySession(session) : null;
return resolve(event);
}
// 로깅 훅
async function logger({ event, resolve }) {
const start = Date.now();
const response = await resolve(event);
const duration = Date.now() - start;
console.log(`${event.request.method} ${event.url.pathname} — ${duration}ms`);
return response;
}
// CORS 훅
async function cors({ event, resolve }) {
const response = await resolve(event);
if (event.url.pathname.startsWith('/api')) {
response.headers.set('Access-Control-Allow-Origin', '*');
response.headers.set('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE');
}
return response;
}
// sequence로 순서대로 실행
export const handle = sequence(logger, auth, cors);
handleError — 에러 로깅
// src/hooks.server.js
export function handleError({ error, event, status, message }) {
// 에러 로깅 (Sentry, LogRocket 등)
console.error(`[${status}] ${event.url.pathname}:`, error);
// 에러 추적 서비스에 보고
// Sentry.captureException(error);
// 사용자에게 보여줄 에러 메시지 반환
return {
message: '예기치 못한 오류가 발생했습니다.',
code: status,
};
}
handleFetch — 서버 측 fetch 수정
// src/hooks.server.js
export async function handleFetch({ event, request, fetch }) {
// 내부 API 호출 시 인증 토큰 자동 추가
if (request.url.startsWith('https://api.internal.com')) {
request = new Request(request, {
headers: {
...Object.fromEntries(request.headers),
'Authorization': `Bearer ${event.locals.token}`,
}
});
}
return fetch(request);
}
클라이언트 훅
// src/hooks.client.js
export function handleError({ error, status, message }) {
// 클라이언트 측 에러 로깅
console.error('클라이언트 에러:', error);
return {
message: '문제가 발생했습니다. 새로고침 해주세요.',
};
}
locals 타입 정의
// src/app.d.ts
declare global {
namespace App {
interface Locals {
user: {
id: string;
name: string;
email: string;
role: 'admin' | 'user';
} | null;
}
interface Error {
message: string;
code?: number;
}
}
}
export {};
면접 포인트
- "handle 훅에서 resolve를 호출하지 않으면?": 라우트 핸들러가 실행되지 않습니다. 이를 활용해 특정 조건에서 요청을 차단하거나 리다이렉트할 수 있습니다.
- "Express 미들웨어와의 차이는?": SvelteKit의 handle은 단일 함수에서 요청과 응답을 모두 처리합니다. sequence로 여러 훅을 조합할 수 있으며, event.locals로 데이터를 전달합니다.
정리
Hooks는 SvelteKit 앱의 모든 요청이 통과하는 관문입니다. 인증 체크, 로깅, CORS 설정, 에러 처리 같은 횡단 관심사를 한 곳에서 관리할 수 있어, 코드 중복을 줄이고 보안을 강화할 수 있습니다.
댓글 로딩 중...