문제 발생
기능 적용 후, 처음에는 이미지 파일들을 대상으로 업로드 테스트를 진행했습니다. 그러던 중 파일의 크기와 종류를 다양하게 하여 대용량 파일이나 고화질 이미지들이 포함된 업로드를 시도하게 되었습니다. 그 결과 업로드 시간이 지나치게 길어지고, 네트워크 환경에 따라 서버 API에서 타임아웃이 발생하는 문제를 겪었습니다.
해결 방법
문제를 해결하기 위해 백엔드 개발자와 논의한 결과, 파일을 청크(Chunk) 단위로 분할하여 업로드하는 방식을 채택했습니다.
이 방법은 대용량 파일을 작은 청크로 나누어 서버에 전송하는 방식으로, 한 번에 전송되는 데이터의 양을 줄여 서버와의 연결이 끊어지는 것을 방지하고, 업로드 안정성을 크게 향상할 수 있습니다. 이를 통해 대용량 파일을 효율적으로 업로드할 수 있게 되었습니다.
파일을 청크 단위로 분할
청크의 크기는 네트워크 상황과 서버의 성능을 고려하여 5MB로 설정하였습니다. 각 파일은 해당 크기로 나누어져 서버에 순차적으로 전송됩니다. 서버 측에서는 각 청크를 받아 최종적으로 하나의 파일로 결합합니다.
async function gf_FILE_CHUNK_HANDLER(api_url, dir_url, param) {
...
const fileInput = document.getElementById("l_img_upload_select");
const files = fileInput.files;
const chunkSize = 5 * 1024 * 1024; // 5MB
let totalSize = 0;
let uploadedSize = 0;
// 파일의 총 크기 계산
for (let file of files) {
totalSize += file.size;
}
// 각 파일을 청크로 나누어 업로드
for (let idx = 0; idx < files.length; idx++) {
let file = files[idx];
const totalChunks = Math.ceil(file.size / chunkSize);
let chunk_idx = 0;
for (let start = 0; start < file.size; start += chunkSize) {
let chunkFormData = new FormData();
chunkFormData.set('file_name', file.name);
chunkFormData.set("files", file.slice(start, start + chunkSize));
chunkFormData.set("current_chunk", chunk_idx);
chunkFormData.set("total_chunks", totalChunks);
try {
const response = await fetch(`/v1/api/customer/img-upload`, {
method: "POST",
body: chunkFormData,
headers: {
"X-CSRFToken": c_t,
},
});
if (!response.ok) {
throw new Error("Network response was not ok");
}
const data = await response.json();
if (data.status.code === 200 || data.status.code === 201) {
let res = data.result;
uploadedSize += file.slice(start, start + chunkSize).size;
chunk_idx++;
if (data.status.code === 200) {
l_chunk_url = res.file_url.replace('dev/', '');
l_chunk_names.push(res.file_name);
l_chunk_exts.push(res.file_ext);
l_chunk_sizes.push(res.file_size);
}
} else {
console.info("error", data.status.msg);
}
} catch (error) {
console.error("Error uploading file:", error);
}
}
}
...
}
해결 후 개선된 점
1. 타임아웃 방지
파일을 청크 단위로 반할하여 한 번에 전송되는 데이터 양을 줄였기 때문에 타임아웃 오류를 해결할 수 있었습니다.
또한, 업로드 도중에 오류가 발생하더라도 해당 청크만 재전송하면 되므로, 전체 파일을 다시 업로드할 필요가 없어졌습니다. 이로 인해 업로드 안정성이 크게 향상되었습니다.
2. 업로드 진행 상황 표시
이전에는 업로드 중에 Spinner를 사용하여 진행 중임을 표시했지만, 사용자는 그 상태가 길어질 경우 무한 로딩에 빠진 것처럼 느껴 수 있었습니다. 그래서 프로그레스바로 변경하여 파일 업로드 진행 상황을 퍼센트와 함께 시각적으로 표시하도록 개선하였습니다. 이를 통해 사용자는 업로드 진행 상황을 한눈에 확인할 수 있어 더욱 직관적이고 편리한 사용자 경험을 제공할 수 있게 되었습니다.
이와 같이 청크 업로드 방식과 프로그레스바를 적용함으로써, 대용량 다중 파일 업로드의 문제를 해결하고 사용자 경험을 크게 향상할 수 있었습니다. 청크 업로드는 서버와의 연결을 효율적으로 관리하고 타임아웃을 방지하며, 파일 업로드가 완료되는 진행 상황을 직관적으로 확인할 수 있도록 도와주는 효과적인 방법이었습니다.
'개발 > FE' 카테고리의 다른 글
Lazy Loading 적용기: 성능 최적화와 사용자 경험 향상 (0) | 2024.11.24 |
---|---|
Vite vs. Webpack : 모듈 번들러의 이해와 비교 (0) | 2024.11.21 |
Monorepo vs. Multirepo: 코드 관리 방식 비교 (0) | 2024.11.19 |
npm vs. pnpm : 패키지 매니저 비교 (0) | 2024.11.19 |
프론트엔드 아키텍처, 방법론, 디자인 패턴 (0) | 2024.11.02 |