WebApp Transfer-Encoding: chunked VS Content-Length

황제낙엽 2009.09.17 11:36 조회 수 : 573 추천:184

sitelink1 http://pungjoo.tistory.com/14 
sitelink2  
sitelink3 http://1 
sitelink4 http://ko 
sitelink5  
sitelink6 http://sitelink1 

0. 들어가면서

Network에서는 전송하고자 하는 콘텐츠(content, 또는 data) 길이를 헤더에 기술하던가 콘텐츠의 끝이라고 서로간에 약속한 데이터를 마지막에 기술하던가 이도 저도 아니면 open된 stream(socket 포함)을 close를 할때 전송의 끝이라고 인식하게 됩니다.

영화를 보면 무전기를 들어 자신이 할 말이 끝났을 때 항상 끝에 '오바(over)'라고 해 자신이 할 말이 끝났음을 상대방에게 알려 줍니다. 이는 통신 규칙입니다.


1.  Content-Length

Content-Length는 응답(response)의 header에 정의 되는 것으로 요청한 내용에 대한 실제적인 결과인 body의 길이가 몇 bytes인가를 의미합니다. 클라이언트(통상 브라우져)는 헤더(header)에 정의된 Content-Length 만큼을 InputStream에서 읽게 됩니다.

[pungjoo@yeonwoo] $ cat Normal.java

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,
           IOException {

     PrintWriter out = response.getWriter();

     try {
          out.print( "data1");
          out.print( "data2");
          out.println();
     } catch (Exception e) {
     } finally {
          if (out != null) {
               try {
                    out.close();
               } catch (Exception e) {
               }
          }
     }
}

[pungjoo@yeonwoo] $

위와 같은 /normal servlet을 호출해 보겠습니다.
참고로 keep-alive의 설정이 서버측면에 되어 있어서 keep-alive를 사용되지 않게 'Connection: close'를 추가했습니다. 이 부분은 HTTP/1.1 부분을 HTTP/1.0으로 하면 동일한 효과를 얻게 됩니다.

[pungjoo@yeonwoo /work/home/pungjoo]$ telnet dev.pungjoo.com 80
Trying 121.124.124.74...
Connected to dev.pungjoo.com.
Escape character is '^]'.
GET /normal HTTP/1.1
Host: dev.pungjoo.com
Connection: close


HTTP/1.1 200 OK
Date: Mon, 09 Mar 2009 03:19:40 GMT
Content-Type: text/plain
Content-Length: 12
Connection: close

data1data2
Connection closed by foreign host.
[pungjoo@yeonwoo /work/home/pungjoo]$

녹색으로 표기된 부분은 직접 입력을 한 부분이고 붉은 색으로 표기된 부분이 응답을 받은 내용중에 Content-Length에 의미를 두는 부분입니다.

클라이언트는 응답 헤더 중에 Content-Length를 통해 Body부분이 12byte로 이루어졌구나 판단 후 Body를 읽을때 InputStream에 12bytes만 읽으라고 정의를 하게 됩니다. 또한 서비스 제공하는 곳에서 첨부파일이 존재할 때 다운로드를 클릭하면 정확히 몇 바이트인 파일을 다운로드 한다고 기술되는 반면 어떤 서비스를 제공하는 곳에서는 '알 수 없는 ..' 이런 류를 보시게 됩니다. 이는 'Content-Length'가 응답 헤더에 있는냐 없느냐에 따라서 구별됩니다.
 
이상한 것은 길이가 12bytes이고 실제 'data1data2'는 총10bytes이므로 2byte의 오차가 생기는데 이는 눈에 보이지 않는 개행문자로 'rn'을 의미하게 됩니다.


2. Transfer-Encoding: chunked

초창기와 비교해 보면 요즘은 정적인 콘텐츠는 거의 없는 실정입니다. 비단 이미지 같은 바이너리도 동적으로 구성되어 제공되는 것이 현실입니다. 서버측에서 서비스 단위로 끊어서 로직을 진행하다 보니 모든 작업이 종료될 때까지 클라이언트는 멍하니 '흰 색'으로 채워진 내용을 보다 순간 '짠..'하고 화면에 나타나는 경우가 있게 됩니다. 이런 부분은 여러가지 요소의 영향으로 발생하는 현상이지만 순수히 Text인 Body(html)의 경우도 심심치 않게 발생하게 됩니다. 따라서 처리된 부분까지라도 그때 그때 클라이언트에 전송해 주면 클라이언트 입장에서 답답함은 조금 사라질 수 있을 것 입니다. (단, 처리되는 순서가 중요할 수 있습니다. )

[pungjoo@yeonwoo] $ cat Chunked.java

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,
           IOException {

     PrintWriter out = response.getWriter();

     try {
          out.print("data1");
          out.flush(); // /normal servlet과 다르게 추가된 부분.
          out.print("data2");
          out.println();
          out.flush(); // /normal servlet과 다르게 추가된 부분.
     } catch (Exception e) {
     } finally {
          if (out != null) {
               try {
                    out.close();
               } catch (Exception e) {
               }
          }
     }
}

[pungjoo@yeonwoo] $


위와 같은 /chunked servlet을 호출해 보겠습니다. /normal servlet과의 차이는 out.flush(); 입니다.

 

 

[pungjoo@yeonwoo /work/home/pungjoo]$ telnet dev.pungjoo.com 80
Trying 121.124.124.74...
Connected to dev.pungjoo.com.
Escape character is '^]'.
GET /chunked HTTP/1.1
Host: dev.pungjoo.com
Connection: close


HTTP/1.1 200 OK
Date: Mon, 09 Mar 2009 05:47:21 GMT
Connection: close
Transfer-Encoding: chunked
Content-Type: text/plain

5
data1
7
data2

0


Connection closed by foreign host.
[pungjoo@yeonwoo /work/home/pungjoo]$


붉은 색으로 표기된 'Transfer-Encoding: chunked' 부분이 헤더에 추가되어 전송이 되면 클라이언트는 처음에 '5'를 읽고 '아..5 bytes. 전송하겠구나'라고 판단 5바이트를 읽고 대기(?)를 하다 '7'을 읽고 '5'와 동일하게 처리하는 것을 반복하다 '0'이 오면 더 이상 전송 받을 것이 없다고 판단하고 스트림 읽기를 중단합니다.

그런데 중요한 것이 web application server는 대체적으로 output-stream에 buffer를 둡니다. 따라서 flush를 한다고 해서 바로 클라이언트로 데이터가 전송되는 것이 아니라 buffer가 정의된 만큼 가득 차거나 더이상 전송할 것이 없을 경우 클라이언트에 데이터가 전송되므로 실질적인 앞서 설명된 효과를 얻기는 어렵습니다.

단, jsp/servlet에서 통상적으로 output을 response.getWriter()를 사용하기 때문에 설명된 것 처럼 작동(?)하지 않는 것이지 response.getOutputStream()를 사용하면 설명된 효과를 얻게 됩니다.


@

 

 

번호 제목 글쓴이 날짜 조회 수
43 세션의 timeout 설정 >> HttpSession.setMaxInactiveInterval() 황제낙엽 2019.07.03 8649
42 jQuery JSON 데이터 통신의 특성 (HttpServletRequest) 황제낙엽 2019.06.23 581
41 [HttpURLConnection] 서버와의 통신 시도 시점 관련 황제낙엽 2019.06.23 650
40 응답 헤더의 Content-disposition 속성 황제낙엽 2019.04.16 901
39 Java에서 User-Agent 파써 사용하기 황제낙엽 2017.11.20 842
38 서버구동시 주기적으로 동작을 수행하는 스레드를 함께 실행하는 서블릿 황제낙엽 2017.08.02 551
37 JSP 파일에서 getOutputStream() has already been called for this response 에러 황제낙엽 2013.04.24 11973
36 [The type HttpUtils is deprecated] javax.servlet.http.HttpUtils 황제낙엽 2013.03.20 628
35 Java에서 URL 다루기 file 황제낙엽 2012.06.24 453
34 HttpServletResponse.setContentType(java.lang.String type) 과 MIME 타입 황제낙엽 2012.04.20 576
33 한글 파일명 깨짐으로 살펴본 다국어 처리 문제 (UTF-8) 황제낙엽 2012.03.22 10508
32 <jsp:include>, include지시자 file 황제낙엽 2011.07.24 498
31 <jsp:include> 액션태그 황제낙엽 2011.07.24 451
30 Servlet의 각종 Listener 사용방법 및 샘플 황제낙엽 2010.10.26 450
29 ServletContext 초기화 및 소멸 황제낙엽 2010.10.26 461
28 ServletConfig 이용하기 황제낙엽 2010.03.15 520
» Transfer-Encoding: chunked VS Content-Length 황제낙엽 2009.09.17 573
26 서블릿 응답 헤더(Response Header) 황제낙엽 2009.09.17 524
25 MultipartRequest (cos.jar)와 서블릿을 이용한 업로드 file 황제낙엽 2009.06.19 713
24 JSP session 정보 얻기 황제낙엽 2009.01.21 492