| fetch | axios | ky | |
|---|---|---|---|
| 번들 크기 | 0kb (내장) | ~14kb | ~3kb |
| 기반 | - | XMLHttpRequest | fetch |
| 인터셉터 | 직접 래핑 필요 | O | O (hooks) |
| 타임아웃 | 직접 구현 필요 | O | O |
| 자동 재시도 | X | X | O (ky.retry) |
| TypeScript | 기본 타입만 | O | O |
fetch는 인터셉터가 없어 토큰 주입·갱신 로직을 매 호출마다 작성해야 합니다.axios는 기능이 충분하지만 XMLHttpRequest 기반이라 번들 오버헤드가 있고, 이미 fetch가 있는 환경에서 중복됩니다.ky는 fetch 기반이라 Next.js 환경과 궁합이 좋고, beforeRequest·afterResponse 훅과 ky.retry가 있어 토큰 갱신 후 원래 요청을 재시도하는 구조를 깔끔하게 구현할 수 있었습니다.const api = ky.create({
prefix: process.env.NEXT_PUBLIC_API_URL,
timeout: 10000,
credentials: "include",
headers: {
"Content-Type": "application/json",
},
hooks: {
beforeRequest: [...],
afterResponse: [...],
},
});
prefix : 모든 API 호출에 베이스 URL 자동 적용timeout : 10초 초과 시 자동 실패 처리credentials: "include" : 토큰 쿠키를 요청에 자동 포함로그인 성공
├── setAccessToken(token) → 인메모리 변수 (XSS 탈취 방지)
└── setAuthCookie(token) → Server Action으로 쿠키 저장 (Proxy 인증용)
| 저장소 | 역할 |
|---|---|
인메모리 (accessToken 변수) |
API 요청 시 Authorization 헤더 주입. 페이지 새로고침 시 초기화됨 |
쿠키 (accessToken) |
Proxy에서 서버 사이드 인증 여부 확인. 새로고침 후에도 유지 |
accessToken은 모듈 스코프 변수로 앱 전체에서 단일 인스턴스로 공유됩니다.
단, 클라이언트 측에서만 유효하며 서버 컴포넌트 요청 시에는 항상 null이므로, 서버 사이드 인증은 쿠키 토큰으로 처리합니다.
beforeRequest — 토큰 자동 주입beforeRequest: [
({ request }) => {
const token = getAccessToken() ?? getCookieToken();
if (token) {
request.headers.set("Authorization", `Bearer ${token}`);
}
},
],
인메모리 토큰을 우선 사용하고, 없으면 쿠키에서 읽어 폴백합니다. 새로고침 직후처럼 인메모리가 비어있는 상황에서도 쿠키 토큰으로 요청이 정상 처리됩니다.