HTTP multipart/form-data raw 데이터는 어떤 형태일까?
Apache HTTP Client를 이용하여 multipart/form-data content-type으로의 요청을 서버로 보내는 유틸을 개발하게 되었다.
흔히 웹 브라우저에서 파일 첨부를 한 후 "저장하기" 버튼을 클릭했을 때의 동작을 Java 코드로 구현하는 것 뿐이다.
client와 server코드를 완성한 후 서버측으로 다음과 같은 정보로 요청을 보냈다.
request URL : http://localhost:8080/file/upload
업로드 파일 : test.txt, test1.txt
로그 레벨을 DEBUG로 설정한 후 파일 업로드 요청을 보내게 되면 다음과 같은 request raw 데이터가 남게 된다.
실제 client 에서는 다음과 같은 데이터를 서버로 보내게 되는 것이다.
multipart/form-data로 데이터를 보낼때의 request header와 body는 위와 같이 이뤄져 있으며 눈여겨 봐야 할 부분은 Content-Type이다.
Content-Type에 multipart/form-data로 지정이 되어 있어야 서버에서 정상적으로 데이터를 처리할 수 있으며 boundary에 지정되어 있는 문자열을 이용하여 전송되는 파일 데이터의 구분자로 사용되는 것을 확인할 수 있다.
boundary의 문자열 중 마지막의 ------WebKitFormBoundaryQGvWeNAiOE4g2VM5-- 값은 다른 값들과 다르게 마지막에 -- 가 붙은 것을 확인할 수 있는데 이는 body의 끝을 알리는 의미이다.
이러한 것들이 모두 HTTP 통신 규격으로 지정되어 있으며 이 규격에 맞게 http header와 body 데이터를 생성한 후 HTTP server에 요청하게 되면 서버에서도 HTTP 통신 규격에 맞게 데이터를 파싱한 후 처리하게 되는 것이다.
HTTP request와 response의 데이터를 좀더 자세하게 살펴보도록 하자.
다음은 개행 문자가 포함되어 있는 HTTP request와 response 이다.
헤더와 헤더를 구분하는 것이 개행문자임을 알 수 있고,
헤더와 바디를 구분하는 것은 개행문자2개
body에 포함되어 있는 파일데이터를 구분하는 것은 boundary라는 것을 알 수 있다.
## HTTP Request Data
POST /file/upload HTTP/1.1[\r][\n]
Content-Length: 344[\r][\n]
Content-Type: multipart/form-data; boundary=Uee--r1_eDOWu7FpA0LJdLwCMLJQapQGu[\r][\n]
Host: localhost:8080[\r][\n]
Connection: Keep-Alive[\r][\n]
User-Agent: Apache-HttpClient/4.3.4 (java 1.5)[\r][\n]
Accept-Encoding: gzip,deflate[\r][\n]
[\r][\n]
--Uee--r1_eDOWu7FpA0LJdLwCMLJQapQGu[\r][\n]
Content-Disposition: form-data; name=files; filename=test.txt[\r][\n]
Content-Type: application/octet-stream[\r][\n]
[\r][\n]
aaaa
[\r][\n]
--Uee--r1_eDOWu7FpA0LJdLwCMLJQapQGu[\r][\n]
Content-Disposition: form-data; name=files; filename=test1.txt[\r][\n]
Content-Type: application/octet-stream[\r][\n]
[\r][\n]
1111
[\r][\n]
--Uee--r1_eDOWu7FpA0LJdLwCMLJQapQGu--[\r][\n]
## HTTP Response Data
HTTPHTTP/1.1 200 OK[\r][\n]
Server: Apache-Coyote/1.1[\r][\n]
Accept-Charset: big5, big5-hkscs, euc-jp, euc-kr...[\r][\n]
Content-Type: text/html;charset=UTF-8[\r][\n]
Content-Length: 7[\r][\n]
Date: Mon, 30 Jun 2014 01:28:19 GMT[\r][\n]
[\r][\n]
SUCCESS
Content-Length가 344byte로 데이터가 많지 않기 때문에 하나의 패킷에 담겨져(기본1500byte) 네트웍을 통해 서버로 갈 것인데 만약 첨부된 파일이 이미지라면 여러 개의 패킷으로 쪼개져 네트웍을 통해 서버에 도착하게 될 것이다.
이처럼 HTTP 통신 원리는 단순하다. 스펙에 맞게 문자를 생성한 후 전송되는 것 뿐이다. 이미지를 첨부한다고 해서 xxx.jpg 파일 자체가 전송되는 것이 아니고 동영상을 첨부한다고 해서 xxx.avi 파일 자체가 전송되는 것이 아니다. 이미지 파일 동영상 파일도 문자로 이루어져 있기 때문에 이 문자들이 HTTP request body에 담겨져 서버로 보내지게 되는 것 뿐이다.
간단한 원리로 데이터를 주고 받는 HTTP 프로토콜이지만 모르고 지나치지 않았으면 하는 생각에 정리한다.
'프로그래밍' 카테고리의 다른 글
Free Java Hotswap DCEVM (3) | 2014.09.01 |
---|---|
이클립스 에러난 행으로 이동 (단축키) (0) | 2014.08.26 |
스프링 빈 등록 (Java 코드 이용) (0) | 2014.08.13 |
Resource files jar에 포함시키기 (META-INF/resources) (0) | 2014.07.25 |
My first Java8 Programming (0) | 2014.06.20 |
bean 엘리먼트의 parent attribute 사용 (0) | 2014.05.22 |
spring util:map 사용 시 key와 value 타입 지정 (0) | 2014.05.17 |
c:import 사용 시 주의사항 (Request method 'POST' not supported) (2) | 2014.05.16 |