Note
HTML5의 FileAPI를 사용하기 위해서는 웹 브라우저가 해당 기능을 제공해야 합니다. 현재 PC 브라우저인 Internet Explorer 10/11, Chrome, Firefox, Safari에서 사용 가능합니다. 안드로이드, IOS 기반 브라우저에서도 사용 가능합니다.
HTML5의 FileAPI와 AJAX을 사용하면 폼 서브밋과는 별도로 파일 업로드를 진행할 수 있습니다. 이 경우 multipart/form-data를 생성할 필요 없이 FileAPI를 사용해 파일 데이터를 직접 읽어서 웹 서버로 전송할 수 있습니다.
FileAPI 클래스 중 FileReader 클래스를 사용해 파일 데이터를 직접 읽을 수 있습니다. 읽은 파일 이름과 파일 데이터를 사용해 AJAX 요청을 생성해 서버로 전송하고 그 응답을 받아 리스트에 출력합니다.
이 같은 방식의 업로드는 HTTP 본문이 파일의 바이너리 데이터로 구성되므로 그 외의 추가 정보는 URL의 GET 파라미터 또는 HTTP 헤더를 통해 서버로 전송할 수 있습니다. TABS Upload는 file-name 이라는 명칭의 헤더에 파일 이름을 전송하는 방식을 사용합니다. 파일 이름은 반드시 encodeURIComponent() 함수를 사용해 인코딩해야 한글 이름이 손상되지 않고 서버로 전송됩니다.
function Uploader(file) {
this._file = file;
this._xhr = new XMLHttpRequest();
this._xhr.addEventListener("load", transferComplete);
// 파일 하나에 대한 업로드를 시작한다.
this.startUpload = function () {
var reader = new FileReader();
var fileName = this._file.name;
var xhr = this._xhr;
// FileReader에서 파일 내용을 모두 읽은 경우 AJAX으로 전송한다.
reader.onload = function(evt) {
xhr.open("POST", "upload.asp", true);
// 파일 이름은 file-name에 명시한다.
xhr.setRequestHeader("file-name", encodeURIComponent(fileName));
xhr.send(evt.target.result);
};
reader.readAsArrayBuffer(file);
}
function transferComplete() {
// 성공적으로 업로드된 경우 UI에 출력한다.
if (this.status == 200) {
var li = document.createElement("li");
li.innerHTML = this.responseText;
document.getElementById("resultList").appendChild(li);
}
}
}
function Upload() {
var uploadFiles = document.getElementById("uploadFiles");
var uploader = new Uploader(uploadFiles.files[0]);
uploader.startUpload();
}
<form>
<input id="uploadFiles" type="file" style="width:300px">
<br />
<br />
<input id="uploadBtn" type="button" value="업로드" onclick="Upload()"/>
<h3>업로드 결과</h3>
<ul id="resultList"></ul>
</form>
위 코드에서 생성된 업로드 AJAX HTTP 요청을 캡처해 보면 아래와 같습니다. file-name 헤더에 파일 이름이 인코딩되어 전송되고 HTTP 본문은 파일 자체 데이터만 전송됩니다.
이 데이터를 ASP 페이지에서 받아서 처리할 수 있는 오브젝트가 TABSUpload4.UploadSingle 오브젝트입니다. 기존 TABSUpload4.Upload 오브젝트는 multipart/form-data 형식의 업로드 데이터를 처리하는 것으로 바이너리 형식의 AJAX HTTP 요청을 처리할 수 없습니다.
POST /upload.asp HTTP/1.1
Accept: */*
file-name: (%EA%B3%B5%EC%9C%A0%EC%9A%A9)%EC%B6%9C%EA%B3%A0%ED%99%95%EC%9D%B8%EC%84%9C(%ED%86%B5%ED%95%A9)_%EC%9D%BC%EC%9A%94%EC%9D%BC.xlsx
Accept-Language: ko-KR
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
Content-Length: 77596
Connection: Keep-Alive
Cache-Control: no-cache
[binary file data]
이러한 방식의 바이너리 업로드 데이터는 하나의 파일 데이터만 전송되고 여타 다른 폼 데이터는 전송되지 않으므로 매우 간단한 코드로 처리될 수 있습니다. TABSUpload4.UploadSingle 오브젝트를 생성한 후 Start 메서드를 호출합니다. Start 에서는 바이너리 데이터를 읽어서 임시 파일 형태로 저장하고 HTTP 헤더로 전달되는 파일 이름을 디코딩합니다. 모든 데이터를 받은 후 Save 또는 SaveAs 메서드를 호출해 원하는 위치로 파일을 옮겨 저장합니다.
<%@ CodePage=65001 Language=VBScript %>
<%
UploadPath = "C:\Temp\Upload"
Set upload = Server.CreateObject("TABSUpload4.UploadSingle")
'하나의 파일에 대한 바이너리 업로드 데이터를 처리한다.
upload.Start "C:\Temp"
'처리한 데이터를 실제 파일로 저장한다.
upload.Save UploadPath, false
Response.Write upload.ShortSaveName
%>
AJAX을 사용한 업로드 UI는 일반적으로 파일 업로드와 폼 데이터 제출(Submit)이 서로 다른 HTTP 요청으로 처리합니다. AJAX으로 파일을 업로드하고 그 결과(파일 고유 키 값)를 받아와서 저장하고 있다가 폼 데이터 제출시 함께 보내 최종 처리를 합니다.
예를 들어 게시판에 글을 쓸 경우 팝업 윈도우에서 이미지 파일 업로드를 AJAX으로 처리하고 그 결과를 폼 페이지로 보냅니다. 글 작성을 완료한 후 제출하게 되면 글 데이터는 DB에 저장하고 이미지 파일은 파일 디렉터리에 저장하게 됩니다. 이 과정에서 사용자가 글 작성을 완료하지 않고 브라우저를 종료한다면 업로드 된 이미지 파일은 게시판 글과 연결되지 않은 채로 서버의 어딘가에 저장되어 있게 됩니다. 즉, 가비지 파일이 생성됩니다.
이 문제를 해결하기 위해 TABS Upload는 TempFileManager라는 오브젝트를 제공합니다. 업로드 완료 후 임시 디렉터리에 저장된 이미지를 TempFileManager에 넣어 둡니다. 최종 폼이 제출되고 글 저장이 될 때 이미지 파일을 최종 목적지로 복사합니다. 최종 폼 제출이 되지 않을 경우 TempFileManager는 일정 시간 뒤 자동으로 해당 파일을 삭제해 서버에 가비지 파일이 생성되지 않도록 합니다. TempFileManager를 사용하기 위해서는 TABS Upload 5 Utility Service가 실행되고 있어야 합니다.
<%@ CodePage=65001 Language=VBScript %>
<%
UploadPath = "C:\Temp\Upload"
Set upload = Server.CreateObject("TABSUpload4.UploadSingle")
'하나의 파일에 대한 바이너리 업로드 데이터를 처리한다.
upload.Start "C:\Temp"
'처리한 데이터를 실제 파일로 저장한다.
upload.Save UploadPath, false
Response.Write upload.ShortSaveName
'AJAX으로 업로드된 파일은 가비지 파일이 될 수 있으므로 TempFileManager에서 일정 시간(5시간) 동안만 유지시킨다.
Set tmgr = Server.CreateObject("TABSUpload4.TempFileManager")
tmgr.AddFile upload.SaveName, 60 * 5
%>