파일 업로드 및 다운로드 📁 파일 업로드 async function uploadFile (file, onProgress ) { const formData = new FormData (); formData.append ('file' , file); formData.append ('category' , 'documents' ); formData.append ('description' , [file.name ](http : try { const response = await [axios.post ](http : headers : { 'Content-Type' : 'multipart/form-data' }, onUploadProgress : (progressEvent ) => { const percentCompleted = Math .round ( (progressEvent.loaded * 100 ) / [progressEvent.total ](http : ); console .log (`업로드 진행률: ${percentCompleted} %` ); onProgress?.(percentCompleted); } }); return [response.data ](http : } catch (error) { console .error ('파일 업로드 실패:' , error); throw error; } } async function uploadMultipleFiles (files ) { const formData = new FormData (); files.forEach ((file, index ) => { formData.append (`files` , file); }); const response = await [axios.post ](http : headers : { 'Content-Type' : 'multipart/form-data' } }); return [response.data ](http : } const fileInput = document .getElementById ('fileInput' );fileInput.addEventListener ('change' , async (event) => { const file = [event.target ](http : if (file) { try { const result = await uploadFile (file, (progress ) => { console .log (`업로드 진행률: ${progress} %` ); }); console .log ('업로드 완료:' , result); } catch (error) { console .error ('업로드 에러:' , error); } } });
📥 파일 다운로드 async function downloadFile (fileId, filename ) { try { const response = await axios.get (`/api/files/${fileId} /download` , { responseType : 'blob' }); const url = window .URL .createObjectURL (new Blob ([[response.data ](http : const link = document .createElement ('a' ); link.href = url; link.setAttribute ('download' , filename); document .body .appendChild (link); [link.click ](http : document .body .removeChild (link); window .URL .revokeObjectURL (url); } catch (error) { console .error ('파일 다운로드 실패:' , error); } }
에러 처리 베스트 프랙티스 🛡️ 포괄적인 에러 처리 function handleApiError (error ) { if (error.response ) { const { status, data } = error.response ; switch (status) { case 400 : console .error ('잘못된 요청:' , data.message ); break ; case 401 : console .error ('인증 실패 - 로그인이 필요합니다' ); window .location .href = '/login' ; break ; case 403 : console .error ('접근 권한이 없습니다' ); break ; case 404 : console .error ('요청한 리소스를 찾을 수 없습니다' ); break ; case 429 : console .error ('요청 한도를 초과했습니다. 잠시 후 다시 시도해주세요' ); break ; case 500 : console .error ('서버 내부 오류가 발생했습니다' ); break ; default : console .error (`서버 오류 (${status} ):` , data.message ); } return { type : 'response' , status, message : data.message }; } else if (error.request ) { console .error ('네트워크 오류: 서버에 연결할 수 없습니다' ); return { type : 'network' , message : '네트워크 연결을 확인해주세요' }; } else { console .error ('요청 설정 오류:' , error.message ); return { type : 'config' , message : error.message }; } } async function apiCallWithRetry (requestFn, maxRetries = 3 , delay = 1000 ) { for (let attempt = 1 ; attempt <= maxRetries; attempt++) { try { return await requestFn (); } catch (error) { const errorInfo = handleApiError (error); if (attempt === maxRetries || errorInfo.type === 'response' ) { throw error; } console .log (`재시도 ${attempt} /${maxRetries} - ${delay} ms 후 다시 시도...` ); await new Promise (resolve => setTimeout (resolve, delay * attempt)); } } } async function fetchUserData (userId ) { return apiCallWithRetry ( () => axios.get (`/api/users/${userId} ` ), 3 , 1000 ); }
성능 최적화 팁 ⚡ 요청 최적화 기법 class ApiService { constructor ( ) { this .pendingRequests = new Map (); } async fetchData (endpoint, options = {} ) { if (this .pendingRequests .has (endpoint)) { this .pendingRequests .get (endpoint).abort (); } const controller = new AbortController (); this .pendingRequests .set (endpoint, controller); try { const response = await axios.get (endpoint, { ...options, signal : controller.signal }); this .pendingRequests .delete (endpoint); return [response.data ](http : } catch (error) { this .pendingRequests .delete (endpoint); if (axios.isCancel (error)) { console .log ('요청이 취소되었습니다:' , endpoint); } else { throw error; } } } cancelAllRequests ( ) { this .pendingRequests .forEach (controller => controller.abort ()); this .pendingRequests .clear (); } } function debounce (func, wait ) { let timeout; return function executedFunction (...args ) { const later = ( ) => { clearTimeout (timeout); func (...args); }; clearTimeout (timeout); timeout = setTimeout (later, wait); }; } const debouncedSearch = debounce (async (query) => { if (query.trim ()) { const results = await axios.get ('/api/search' , { params : { q : query } }); console .log ('검색 결과:' , [results.data ](http : } }, 300 ); class RateLimitedApi { constructor (maxConcurrent = 5 ) { this .maxConcurrent = maxConcurrent; this .running = 0 ; this .queue = []; } async request (config ) { return new Promise ((resolve, reject ) => { this .queue .push ({ config, resolve, reject }); this .processQueue (); }); } async processQueue ( ) { if (this .running >= this .maxConcurrent || this .queue .length === 0 ) { return ; } this .running ++; const { config, resolve, reject } = this .queue .shift (); try { const response = await axios (config); resolve (response); } catch (error) { reject (error); } finally { this .running --; this .processQueue (); } } } const rateLimitedApi = new RateLimitedApi (3 );
🎯 마무리 Axios는 JavaScript 생태계에서 가장 강력하고 유연한 HTTP 클라이언트 라이브러리입니다. 이 가이드에서 다룬 내용들을 실제 프로젝트에 적용하면 더욱 안정적이고 효율적인 API 통신을 구현할 수 있습니다.
핵심 포인트 정리 ✅ 인스턴스 활용 : 공통 설정을 가진 인스턴스로 코드 중복 제거 ✅ 인터셉터 사용 : 인증, 로깅, 에러처리 등 공통 로직 처리 ✅ 에러 처리 : 다양한 에러 상황에 대한 체계적인 대응 ✅ 성능 최적화 : 요청 취소, 디바운싱, 동시 요청 제한 ✅ 타입 안정성 : TypeScript와 함께 사용하여 더욱 안전한 코드 작성
Axios를 마스터하여 더 나은 웹 애플리케이션을 만들어보세요! 🚀