파일 업로드 및 다운로드📁 파일 업로드// 단일 파일 업로드async function uploadFile(file, onProgress) { const formData = new FormData(); formData.append('file', file); formData.append('category', 'documents'); formData.append('description', [file.name](http://file.name)); try { const response = await [axios.post](http://axios.post)('/api/upload', formData, { headers: { 'Content-Type': 'multipart/form-data' }, onUploadProgress: (progressEvent) => { const percentCompleted = Math.round( (progressEvent.loaded * 100) / [progressEvent.total](http://progressEvent.total) ); console.log(`업로드 진행률: ${percentCompleted}%`); onProgress?.(percentCompleted); } }); return [response.data](http://response.data); } 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://axios.post)('/api/upload/multiple', formData, { headers: { 'Content-Type': 'multipart/form-data' } }); return [response.data](http://response.data);}// 사용 예시const fileInput = document.getElementById('fileInput');fileInput.addEventListener('change', async (event) => { const file = [event.target](http://event.target).files[0]; 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' }); // Blob을 사용하여 파일 다운로드 트리거 const url = window.URL.createObjectURL(new Blob([[response.data](http://response.data)])); const link = document.createElement('a'); link.href = url; link.setAttribute('download', filename); document.body.appendChild(link); [link.click](http://link.click)(); document.body.removeChild(link); // 메모리 정리 window.URL.revokeObjectURL(url); } catch (error) { console.error('파일 다운로드 실패:', error); }}
에러 처리 베스트 프랙티스🛡️ 포괄적인 에러 처리// 에러 타입별 처리 함수function handleApiError(error) { if (error.response) { // 서버가 응답했지만 상태 코드가 2xx 범위를 벗어남 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 }; }}// 재시도 로직이 포함된 API 호출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, // 최대 3번 재시도 1000 // 1초 간격 );}