과제 제출이나 프로젝트 스크린샷 업로드는 기다림이 생기는 작업입니다. 진행률과 재시도 방식을 명확히 보여 주어야 학생들이 불안해하지 않습니다.
이번 글에서 새로 나오는 용어
- 멀티파트 전송: 파일을 여러 조각으로 나눠 보내는 HTTP 방식으로, 폼에
enctype="multipart/form-data"를 지정해야 합니다. - 진행률 이벤트: 업로드 중
onprogress로 전달되는 정보로, 전송된 바이트를 기준으로 퍼센트를 계산합니다. - XMLHttpRequest: 세밀한 업로드 제어와 진행률 이벤트를 제공하는 오래된 브라우저 API입니다.
AbortController/xhr.abort(): 사용자가 중단을 누르면 네트워크 요청을 즉시 끊어 주는 취소 도구입니다.
개념
멀티파트 전송(multipart transfer, 다중 부분 전송)은 파일을 담아 보내는 HTTP 방식입니다. 폼에 enctype="multipart/form-data"를 설정해야 브라우저가 파일을 올바로 전송합니다. 진행률(progress, 완료 비율)은 업로드 중 전송된 바이트 비율로 계산합니다. XMLHttpRequest나 fetch + ReadableStream으로 이벤트를 받을 수 있습니다. 취소는 xhr.abort()나 AbortController(요청 취소 컨트롤러)로 구현해야 사용자 선택을 바로 반영할 수 있습니다.
코드
폼, 진행률 처리, 서버 액션을 순서대로 정리합니다.
<script>
let pending = false;
let progress = 0;
function handleUpload({ action, form }) {
const xhr = new XMLHttpRequest();
xhr.upload.onprogress = (event) => {
if (!event.lengthComputable) return;
progress = Math.round((event.loaded / event.total) * 100);
};
xhr.onloadstart = () => { pending = true; };
xhr.onloadend = () => { pending = false; progress = 0; };
xhr.open('POST', action);
xhr.send(new FormData(form));
return () => xhr.abort();
}
</script>
<form method="POST" enctype="multipart/form-data" use:enhance={handleUpload}>
<input type="file" name="attachments" accept="image/*,application/pdf" multiple required />
<textarea name="comment" placeholder="메모" rows="3"></textarea>
<button type="submit" disabled={pending}>{pending ? '업로드 중' : '제출'}</button>
</form>
<div class="progress" aria-live="polite">
<div class="bar" style={`width:${progress}%`}>
<span>{progress}%</span>
</div>
</div>
// src/routes/(app)/uploads/+page.server.ts
export const actions = {
default: async ({ request, locals }) => {
const data = await request.formData();
const files = data.getAll('attachments');
if (files.length > 5) {
return fail(400, { error: '파일은 최대 5개까지 업로드 가능합니다.' });
}
await saveFiles(locals.user.id, files);
return { success: true };
}
};
handleUpload에서 반환한 함수가 컴포넌트가 파괴될 때 실행되어 업로드를 취소합니다. 서버에서는 파일 수와 용량을 다시 확인해 악의적인 요청을 막아야 합니다.
왜 중요한가
대용량 파일 업로드는 실패 가능성이 높습니다. 진행률과 취소 버튼이 없으면 사용자가 브라우저를 닫아 버릴 수 있습니다. 명확한 상태 표시와 재시도 경로를 제공하면 교내 과제 제출 페이지나 콘테스트 자료 업로드에서도 불필요한 문의를 줄일 수 있습니다.
실습
- 따라 하기:
use:enhance={handleUpload}패턴으로 멀티 파일 폼을 만들고 진행률 바를 표시한다. - 확장하기: 취소 버튼과 재시도 버튼을 추가해
xhr.abort()후 상태를 초기화한다. - 디버깅: 진행률이 0%에서 멈추면
event.lengthComputable과enctype설정을 확인한다. - 완료 기준: 5개 이하 파일 업로드가 성공하고, 실패 후 다시 시도할 수 있다.
마무리
업로드 흐름을 정리하면 사용자가 기다리는 동안에도 안심할 수 있습니다. 다음 편에서는 컴포넌트 접근성과 반응형 내비게이션을 점검해 전체 경험을 다듬습니다.
💬 댓글
이 글에 대한 의견을 남겨주세요