티스토리 뷰

1) file upload방법의 이해

file upload

  • form태그의 데이터를 보낼 때, file input 방식으로 업로드가 가능합니다. file type에도 name으로 이름을 지정해야 서버에서 이를 인식해서 데이터를 얻을 것입니다.
  • 이전처럼 문자열 기반의 데이터를 보내는 것과는 다르게 file은 바이너리 형태의 데이터를 보냅니다.
  • 아래는 input type file인 경우 예제입니다.

<input type="file" name="reviewImg" id="reviewImageFileOpenInput" accept="image/*">

 

  • 클라이언트 입장에서는 file을 올린다고 해서 크게 다르진 않습니다. input의 type file로 설정하고 name설정을 해서 클라이언트/서버 간의 보낼 데이터의 이름을 지어주면 됩니다. 그리고 서버는 해당 name을 기준으로 클라이언트가 보낸 데이터들을 구분해서 처리합니다.
  • id는 클라이언트에서만 처리하거나 제어할 때 필요한 것입니다. 예를 들어서 input type의 어떤 이벤트를 등록을 하고 싶을 때 사용합니다.
  • accept는 허용 가능한 file type을 결정지을 수 있습니다. 예를 들어 위와 같이 설정하면 이미지 파일을 제외한 텍스트 파일 등은 업로드할 수 없습니다. 이와 관련해 유용한 속성이 여러 개 있는데, 브라우저 지원이 제한적인 상태이므로 참고해서 사용해야 합니다. caniuse.com 같은 사이트에서 브라우저 지원 범위를 확인할 수 있습니다. accept는 다중으로 설정할 수 있습니다. (ex) accept="image/png, image/jpeg")

<div class="formWrap">

    <form action="/join" method="post" id="myform">

        <div class="inputWrap">

            <div class="email">

                <span> Email </span> <input type="text" name="email"><br/>

            </div>

            <div class="password">

                <span> Password </span> <input type="password" name="password"><br/>

            </div>

        <input type="file" name="reviewImg" accept="image/*">

        </div>

        <input class="sendbtn" type="submit">

    </form>

</div>

위와 같이 파일 선택을 누르면 오른쪽 창이 나타나고 설정한대로 image 파일만 넣을 수 있도록 되어 있습니다.

파일을 선택하여 열기를 누르면 DOM으로 조작을 하지 않아도 화면에 자동으로 추가됩니다. 하지만 submit을 하지 않은 상태이므로 아직 서버에는 날아가지 않고 클라이언트단에서만 이렇게 보입니다.

 

  • 이렇게 해서 서버로 날아간 input(file)은 일반적인 태그들과는 Content-Type이 다릅니다.
  • 일반적인 form 데이터를 전송 시에 HTTP Header에는 기본적으로, 'application/x-www-form-urlencoded' 라는 정보로 노출 됩니다. (ex) Content-Type:application/x-www-form-urlencoded)
  • 그런데, file을 전송할 때는 좀 다릅니다. 아래처럼 Form 태그의 속성으로, enctype multipart/form-data로 지정해야 합니다. (ex) Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7rKYKhIWaTrjvGi1)
  • 여기서 다루지는 않지만, 서버에서는 multipart/form-data를 처리할 수 있도록 합니다. 그래야 바이너리 형태로 데이터를 전송할 수 있습니다.

<div class="formWrap">

    <form action="/join" method="post" id="myform" enctype="multipart/form-data">

        <div class="inputWrap">

            <div class="email">

                <span> Email </span> <input type="text" name="email"><br/>

            </div>

            <div class="password">

                <span> Password </span> <input type="password" name="password"><br/>

            </div>

        <input type="file" name="reviewImg" accept="image/*">

        </div>

        <input class="sendbtn" type="submit">

    </form>

</div>

 

  • multipart/form-data의 실제 데이터를 서버로 어떻게 전송이 될까요? 크롬 개발자도구의 network탭에서 요약된 정보를 통해서 이를 이해할 수 있습니다. 서버에서는 multipartboundary를 통해 파싱을 해서 데이터를 뽑고 추출을 합니다.

------WebKitFormBoundaryiUIOhJXAwxorM25j

Content-Disposition: form-data; name="email"

 

werwerw@sefdsf.com

------WebKitFormBoundaryiUIOhJXAwxorM25j

Content-Disposition: form-data; name="password"

 

werwerwerwerwer

------WebKitFormBoundaryiUIOhJXAwxorM25j

Content-Disposition: form-data; name="reviewImg"; filename="A_Pen_by_younjisu.png"

Content-Type: image/png

 

------WebKitFormBoundaryiUIOhJXAwxorM25j--

 

  • 특이한 점은, 아래와 같이 WebKitFormBoundaryiUIOhJXAwxorM25j 라는 어떤 구분정보를 기준으로 데이터가 노출되고 있습니다. 다른 input 데이터들과 같이 서버로 보내야 한다면, 아래와 같이 html페이지를 구성할 수 있을 겁니다.
  • 실제로는 파일을 보낼 때는, 보통 다른 데이터와 별도로, 먼저 보내는 경우도 많습니다.

생각해보기

  • file upload Ajax기술로 구현할 수 있을까요? -> 네 가능합니다. (ex) FormData 속성)
  • 약간 더 복잡한 처리를 해야하지만, FormData라는 속성을 이용하면 좀더 쉽게 구현할 수가 있습니다. 여기를 참고하세요

참고 자료

[참고링크] Using FormData Objects

https://developer.mozilla.org/en-US/docs/Web/API/FormData/Using_FormData_Objects#Sending_files_using_a_FormData_object

[참고링크] file input 처리하는 방식 설명

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file

[참고링크] multipart 보낼때 데이터 구분에 대한 내용

https://stackoverflow.com/questions/4526273/what-does-enctype-multipart-form-data-mean

 

Comments