FE/BOOK

[HTTP 완벽가이드] 15장 엔터티와 인코딩

<zinny/> 2025. 1. 15. 20:12
728x90

더보기

엔터티(Entity)란 무엇인가요?

**엔터티(Entity)**는 데이터베이스나 소프트웨어 개발에서 사용되는 개념으로, 독립적으로 존재하는 객체 또는 데이터 단위를 의미합니다. 엔터티는 실제 세계의 개념, 사물, 사람, 또는 이벤트를 표현할 수 있습니다.

 

HTTP가 보장하는 것

- 객체는 올바르게 식별되므로 브라우저나 다른 클라리언트는 콘텐츠를 바르게 처리할 수 있다. 

- 객체는 올바르게 압축이 풀릴 것이다. 

- 객체는 항상 최신이다. 

- 사용자의 요구를 만족할 것이다. 

- 네트워크 사이를 빠르고 효율적으로 이동할 것이다. 

- 조작되지 않고 온전하게 도착할 것이다. 

 

HTTP는 콘텐츠를 나르기 위해 라벨링된 엔터티를 사용한다. 

 

1. 메지지는 컨테이너, 엔터티는 화물

HTTP 메시지를 컨테이너라고 한다면, HTTP엔터티는 메시지의 실질적인 화물이다. 

 

a, Content-Type : 엔터티에 의해 전달된 객체의 종류 

b. Content-Length : 전달되는 메시지의 길이나 크기

c. Content-Language : 전달되는 객체와 대응되는 자연어

d. Content-Encoding : 객체 데이터에 대해 행해진 변형

e. Content-Location : 요청 시점을 기준으로, 객체의 또 다른 위치

f. Content-Range : 만약 엔터티가 부분 엔터티라면, 전체의 어느 부분에 해당하는지

g. Content-MD5 : 엔터티 본문의 콘텐츠에 대한 체크섬

h. Last-Modified : 서버에서 콘텐츠가 생성 혹은 수정된 날

i. Expires : 만료일

j. Allow : 어떤 요청 메서드가 허용되는지

k. ETag : 인스턴스에 대한 고유 검사기 ( 엔터티 헤더로 정의되어 있지는 않지만 중요함 )

l. Cache-Control: 캐시 관련 처리 ( 엔터티 헤더로 정의되어 있지는 않지만 중요함 )

 

1.1 엔터티 본문

엔터티 본문에는 가공되지 않은 데이터만을 담고 있다. 엔터티 헤더는 데이터의 의미에 대해 설명할 필요가 있다. 

엔터티 본문은 헤더 필드의 끝을 의미하는 빈 CRLF줄 바로 다음부터 시작한다. 콘텐츠가 어떤 형식은 상관 없이 CRLF바로 다음에 위치한다. 


2. Content-Length 

Content-Length 는 메시지의 엔터티 본문의 크기를 바이트 단위로 나타내며, 어떻게 인코딩 되었든 상관없이 크기를 표현할 수 있다. 압축된 파일의 경우 압축된 후의 크기를 표현한다. 

Content-Length는 메시지를 청크 인코딩으로 전송하지 않는 이상 엔터티 본문을 포함한 메시지에서는 필수적으로 있어야 한다. 특히 서버 충돌로 인해 메시지가 짤린 경우를 검사하기 위해 필요하다. 

 

2.1 잘림 검출 

예전 HTTP는 커넥션이 닫힌 것을 보고 메시지가 끝났음을 인지했다. Content-Length가 없으면 커넥션이 정상적으로 닫힌건지, 서버 충돌로 인해 메시지가 잘려서 닫힌건지 구분하지 못한다. 

특히 캐싱 프락시 서버에서 큰 문제를 나타내는데 캐시가 잘린 메시지를 수신했으나 잘린것을 인지하지 못한다면, 결함 있는 콘첸트를 저장하고 지속적으로 제공하게 될 것이다. 잘린 메시지를 캐시하는 위험을 줄이기 위해서 캐싱 프락시 서버는 명시적으로 Content-Length 헤더를 갖지 않은 HTTP본문은 보통 캐싱하지 않는다. 

 

2.2 잘못된 Content-Length

초창기 클라이언트와 서버들 중 일부는 Content-Length의 계산과 관련된 버그가 있기 때문에 오작동을 탐지하고 교정을 시도한다. 

공식적으로 HTTP/1.1 사용자 에이전트는 잘못된 길이를 받고 사실을 인지한 경우 사용자에게 알려주게 되어있다. 

 

2.3 Content-Length 와 지속 커넥션 (Persistent Connection)

응답이 지속 커넥션을 통해서 온 것이라면 또 다른 HTTP응답이 즉시 뒤를 이을 것이다. Content-Length헤더는 클라리언트에게 메시지하나가 어디서 끝나고 다음시작은 어디인지 알려준다. 커넥션이 지속적이기 때문에 클라리언트는 커넥션이 닫힌 위치를 근거로 메시지의 끝을 인식하는 것은 불가능 하기 때문이다. 

 

더보기

Content-Length헤더 없는 지속 커넥션을 만날 수 있는 하나의 상황은 청크 인코딩을 사용 할 때이다. 

청크 인코딩은 데이터를 특정한 크기를 갖는 일련의 청크들로 쪼개서 보낸다. 엔터티 전체의 크기를 알 수 없더라도 서버는 청크 인코딩을 통해서 엔터티의 정의된 크기의 조각들로 전송할 수 있다. 

 

2.4 콘텐츠 인코딩

HTTP는 보안을 강화하거나 압축을 통해 공간절약을 할 수 있도록 본문을 인코딩할 수 있다. 본문이 인코딩 되어있다면 Content-Length는 인코딩된 길이를 바이트 단위로 정의한다. 인코딩 전 크기를 보내는 경우 지속 커넥션일때 심각한 오류를 유발하기 때문에 주의해야 한다. 

 

2.5 엔터티 본문 길이 판별을 위한 규칙

규칙은 나열된 순서대로 적용되어야 한다. 

 

a. 본문을 갖는 것이 허용되지 않는 특정 타입의 HTTP 메시지 에서는 Contnet-Length 헤더가 무시된다. 예시로는 HEAD응답은 본문을 갖지 않는다

b. 메시지가 Transfer-Encoding 헤더를 포함하고 있다면(기본 HTTP 'identity' 인코딩과는 다른), 메시지가 커넥션이 닫혀서 먼저 끝나지 않는 이상 엔터티는 '0바이크 청크'라 불리는 특별한 패턴으로 끝나야 한다. 

c. Transfer-Encoding헤더가 존재하지 않는 이상 Content-Length는 본문의 길이를 담게된다. 만약 identity가 아닌 Transfer-Encoding헤더를 가지고 있다면 Content-Length헤더를 무시해야 한다. 

d. multipart/byteranges 미디어 타입을 사용하고 Content-Length가 없다면 멀티파트 메시지의 각 부분은 각자가 스스로의 크기를 정의할 것이다. 멀티파트는 자신의 크기를 스스로 결정할 수 있는 유일한 엔터티 본문 유형이다. 

f. 위 규칙에 해당되는게 없다면, 엔터티는 커넥션이 닫힐 때 끝난다. 서버만이 메시지가 끝났음을 알리기 위해서 커넥션을 닫을 수 있다.

g. HTTP/1.0 호환을 위해서 본문을 가진 HTTP/1.1요청은 Content-Length헤더도 가지고 있어야 한다. 1.1 명세는 요청에 본문은 있디만 Content-Length가 없는경우, 메시지의 길이 판별을 할 수 없다면 400응답을, 유효한 Content-Length를 요구하고 싶다면 411응답을 보내야 한다.


3. 엔터티 인증(다이제스트)

HTTP는 여러가지 이유(불완전한 프락시, 버그많은 중개자 프락시 등등 )로 메시지의 일부분이 전송 중에 변형되는 일이 일어난다. 엔터티 본문 데이터에 대한 의도하지 않은 변형을 감지하기 위해서 최초 엔터티가 생성될 때 송신자는 데이터에 대한 체크섬을 생성할 수 있으며, 수신자는 그 체크섬으로 기본적인 검사를 할 수 있다. 

 

Content-MD5헤더는 서버가 엔터티 본문에 MD5알고리즘을 적용한 결과를 보내기 위해 사용된다. 응답을 처음만든 서버만이 헤더를 계산해서 보내야 하며, 중간에 있는 프락시나 캐시는 헤더를 변경 || 추가 해서는 안된다. 종단 간 무결성을 검증하는 목적을 손상시키기 때문이다. 

Content-MD5헤더는 콘텐츠 인코딩의 적용은 끝났지만 전송 인코딩은 적용하지 않은 엔터티 본문에 대한 MD5를 담고 있다. 메시지 무결성을 검증하는 클라이언트는 전송인코딩을 디코딩하고, 디코딩된 엔터티 본문에 대해 MD5를 계산해야 한다. 

MD5는 문서의 위치를 빠르게 알아내고 콘텐츠의 중복 저장 방지를 위한 해시 테이블의 키로 이용될 수 있다. 이런 활용 가치에도 불구하고 Content-MD5헤더는 자주 전송되는 편은 아니다. 


4. 미디어 타입과 차셋(Charset)

context-type 헤더 필드는 엔터티 본문의 MIME 타입을 기술한다. Context-Type의 값은 인터넷 할당 번호 관리기관에 등록된 표준화된 MIME 타입이다. 엔터티가 콘텐츠 인코딩을 거친 경우에도 Context-Type 헤더는 인코딩 전의 엔터티 본문 유형을 명시할 것이다.

더보기

MIME 타입은

전달되는 데이터 매체의 기저 형식의 표준화된 이름으로,

주 미디어 타입 ( 텍스트, 이미지, 오디오 등 ) 으로 시작해서 미디어 타입을 구체적으로 서술하는 부 타입으로 구성된다. 

ex) text/html, text/plain, image/gif....

4.1 텍스트 매체를 위한 문자 인코딩 

Context-Type 헤더는 내용 유형을 자세히 지정하기 위한 선택적 매개변수도 지원한다. 엔터티의 비트 집합을 텍스트 파일의 글자들로 변환하기 위한 'charset' 매개변수가 대표적 예이다.

 

4.2 멀티파트 미디어 타입

MIME 멀티파트 이메일 메시지는 서로 붙어있는 여러개의 메시지를 포함, 하나의 복합 메시지로 보내진다. 각 구성요소는 자족적을 자신에 대해 서술하는 헤더를 포함한다.

HTTP는 멀티파트 본문도 지원한다. 하지만 일반적으로 폼을 채워서 제출할때, 문서의 일부분을 실어나르는 범위 응답을 할때 사용된다.

 

4.3 멀티파트 폼 제출

HTTP 폼을 채워서 제출하면 가변 길이 텍스트 필드 와 업로드 될 객체는 각각이 멀티파트 본문을 구성하는 하나의 파트가 되어서 보내진다. 


5. 콘텐츠 인코딩

느린속도로 연결된 클라이언트에게 큰 HTML 문서를 전송할때, 전송시간을 줄이기 위해 압축을 하는 행위

허가받지 않은 제삼자가 볼 수 없도록 콘텐츠를 암호화 하거나 뒤섞는 행위

이런 종류의 인코딩이 있다.

 

5.1 콘텐츠 인코딩 과정

a. 웹 서버가 원본 Content-type과 Context-Length헤더를 수반한 원본 응답 메시지를생성

b. 인코딩 서버가 인코딩된 메시지를 생성한다. 

    -> 인코딩된 메시지는 Content-Type은 같고 Context-Length는 다르다.

    -> 인코딩 서버는 Context-Encoding 헤더를 추가한다. 

c. 클라이언트는 인코딩된 메시지를 받아 디코딩하고 원본을 얻는다.

 

5.2 콘텐츠 인코딩 유형

HTTP는 표준 콘텐츠 인코딩 유형을 정의, 확장 인코딩 추가도 허용한다. 인코딩은 각 콘텐츠 인코딩 알고리즘에 고유한 토큰을 할당하는 IANA를 통해 표준화 된다. Context-Encoding 헤더는 표준화된 토큰 값을 이용해, 인코딩에 사용된 알고리즘을 기술한다.

더보기

콘텐츠 인코딩 값

- gzip : GNU zip 인코딩이 적용

- compress: 유닉스 파일 압축 프로그램인 'compress'가 실행

- deflate: zlib 포멧으로 압축

- idnetity: 어떤 인코딩도 수행하지 않음 ( Content-Encoding 헤더가 없는 것과 동일) 

 

5.3 Accept-Encoding 헤더

서버에서 클라이언트가 지원하지 않는 인코딩을 사용하는 것을 막기 위해, 클라이언트는 자신이 지원하는 인코딩 목록을 Accept-Encoding 요청 헤더를 통해서 전달한다.

  • Accept-Encoding 요청 헤더가 없다면 어떤 인코딩이든 가능하다는 의미이다 ( Accept-Encoding: * )
  • Accept-Encoding 필드는 지원되는 인코딩들을 쉼표로 구분한다. 
  • 클라이언트는 각 인코딩에 Q(quality) 값으로 상대적인 선호도를 나타낼 수 있다. ( 0.0 ~ 1.0 )
  • identity 인코딩은 오직 Accept-Encoding 헤더에만 존재할 수 있다 (아닌 것 같은데 이야기 필요해보임) 

6. 전송 인코딩 ( 청크 인코딩 )

전송 인코딩은 엔터티 본문에 적용되는 가역적 변환이지만, 구조적인 이유에서 적용되는 것이며 콘텐츠의 포멧과는 독립적이다.

HTTP가 버전이 올라가면서 잘 안쓰는 방식이 됨

 

6.1 안전한 전송

전송 인코딩은 네크워크를 통한 안전한 전송을 위해 존재한다.

 

전송된 메시지의 본문이 문제를 일으키는 이유 중 대표적인 두가지

  1. 알 수 없는 크기
    메시지 본문의 최종 크기를 판단할 수 없을때, 즉 서버가 사이즈를 알기 전에 데이터 전송을 시작할때 서버는 데이터의 끝을 알리는 특별 종결 꼬리말을 포함시켜 전송 인코딩으로 데이터를 보내려 시도한다.
  2. 보안
    공용 전송 네트워크로 메시지 콘텐츠를 보내기 전에 전송 인코딩을 사용해 알아보기 어렵게 뒤섞어 버리는 방법도 있다. SSL같은 전송계층 보안방식이 있어 전송 인코딩 보안은 흔하지 않다.

 

6.2 Transfer-Encoding 헤더

전송 인코딩을 제어하고 서술하기 위해 정의된 두가지 헤더

  1. Transfer-Encoding : 안전한 전송을 위해 어떤 인코딩이 메시지에 적용되었는지 수신자에게 알려준다.
  2. TE : 어떤 확장된 전송 인코딩을 사용할 수 있는지 알려주기 위해 요청 헤더에 사용한다.

모든 전송 인코딩 값은 대소문자가 구별되고, 최신 HTTP 명세는 하나의 전송 인코딩, 즉 청크 인코딩만을 정의했다.

TE헤더는 선호도 Q값을 가질 수 있지만, 청크 인코딩에 대해 Q값이 0.0을 갖는 것을 금지한다.

 

6.3 청크 인코딩

  • 메시지를 일정 크기의 청크로 쪼갠다
  • 각 청크를 순차적으로 보낸다. ( 버퍼에 담은 뒤 한 청크와 그 크기를 함께 보낼 수 있다.)
  • 본문 전체를 모두 보낼 때 까지 반복한다. 
  • 청크 인코딩은 본문이 아닌 메시지의 속성임에 주목해야 한다.

 

클라이언트와 서버 사이의 커넥션이 지속적이지 않으면 클라이언트는 자신이 읽고 있는 본문의 크기를 알 필요가 없다. 서버가 커넥션을 닫을 때까지를 본문으로 간주하고 읽으면 된다. 

 

지속 커넥션에서는 본문을 쓰기전 Context-Length 헤더에 본문의 길이를 담아서 보내줘야 한다. 콘텐츠가 동적으로 생성되는 경우에는 본문의 길이를 알아내는 것이 불가능 하다. 

청크 인코딩을 사용하는 경우, 서버는 크기가 0인 청크로 본문이 끝났음을 알리고, 다음 응답을 위해 커넥션을 열린 채로 유지할 수 있다.  

 


7. 시간에 따라 바뀌는 인스턴스

웹 객체는 정적이지 않다. 같은 URL은 시간에 따라 다른 버전의 객체를 가리킬 수 있다. 

HTTP프로토콜은 어떤 특정한 종류의 요청이나 응답을 이루는 방법들을 정의하는데, 이것은 인스턴스 조작이라고 불리며 객체의 인스턴스에 작용한다. 대표적인 두가니는 범위 요청델타 인코딩이다.

 

인스턴스는 시간에 따른 스냅샷이다


8. 검사기와 신선도

조건부 요청의 흐름

  • 클라이언트가 처음에 리소스 사본을 갖고 있지 않아, 서버에게 달라고 요청을 보낸다.
  • 서버는 리소스의 버전을 1로 응답한다.
  • 클라이언트는 사본을 캐시한다. 
  • 문서가 클라이언트에서 만료되면, 클라이언트는 서버에게 최신 사본을 요구하고, 변경되지 않았다면 캐시된 사본을 사용 한다.

즉 조번부 요청은 클라이언크가 서버에게 자신이 갖고 있는 버전을 말해주고 검사기를 사용해 자신의 사본이 더 이상 유효하지 않을 때만 사본을 보내달라고 요청하는 것이다. 


9. 범위 요청과 델타 인코딩

9.1 범위 요청

만약 무언가 다운로드 중 네크워크 문제로 커넥션이 방해 받은 경우, 범위 요청을 이용해서 다운 받다가 실패한 엔터티를 일부 혹은 범위로 요청함으로써 다운로드를 중단된 시점에서 재개할 수 있다. 즉 범위 요청은 클라이언트가 문서의 일부분이나 특정 범위만 요청하는 것이다. 

  • Range: bytes=4000- (Range 헤더를 사용하여 요청 할 수 있다)

모든 서버가 범위 요청을 받아들일 수 있는 것은 아니다 ( 하지만 많은 경우 가능하다) 서버는 클라이언트에게 자신이 범위를 받아들일 수 있는지 응답에 Accept-Range헤더를 포함시키는 방법으로 알려줄 수 있다. 

 

범위 요청은 객체의 특정 인스턴스를 클라이언트와 서버 사이에서 교환하는 것이기 때문에 인스턴스 조작의 일종이라는 것에 주의해야 한다. 범위 요청은 오직 클라이언트와 서버가 같은 버전의 문서를 갖고 있을 때만 의미가 있다.

 

9.2 델타 인코딩

서버가 클라이언트에게 새 페이지 전체를 보내는 대신, 페이지에 대한 클라이언트의 사본에 대해 변경된 부분만을 서버가 보낸다면, 클라이언트는 좀더 빨리 페이지를 얻릉 수 있을 것이다. 즉 델타 인코딩은 객체 전체가 아닌 변경된 부분에 대해서만 통신하여 전송량을 최적화 하는 HTTP 프로토콜의 확장이다.

 

델타 인코딩도 어떤 객체의 특정 인스턴스들에 대한 클라이언트와 서버사이의 정보 교환에 의존하지 때문에 일종의 인스턴스 조작이다. 

 

델타 인코딩의 매커니즘 

 

  • 클라이언트는 페이지의 어떤 버전을 가지고 있는지(= 클라이언트가 최신버전에 대한 텔타를 받아들일 의사가 있음을 밝히는 행위), 현재 버전에 델타를 적용하기 위해 어떤 알고리즘을 알고 있는지를 서버에게 말해주어야 한다.
  • 서버는 클라이언트가 갖고 있는 버전을 가지고 있는지, 어떻게 최신 버전과 클라인언트의 버전 사이의 델타를 계산할 것인지 확인해야 한다.
  • 그리고 델타를 계산 후 클라이언트에게 보내주고, 델타를 보내고 있음을 알리고, 페이지의 최신 버전에 대한 새 식별자를 명시해야 한다.

클라이언트는 자신이 갖고 있는 버전에 대한 유일한 식별자를 If-None-Match 헤더에 담는다. 이것은 서버에게 ' 니가 가진 최신 버전에 페이지가 이것과 같은 ETag를 갖고 있지 않으면 최신 버전 페이지를 보내' 라고 말하는 방식이다. 

클라이언트는 A-IM(Accept-Instance-Mainpulation)헤더를 보내서 델타를 받아들일 수 없음을 알릴 수도 있다. 

 

클라이언트는 A-IM헤더를 사용해서 받아들일 수 있는 인스턴스 조작의 종류를 명시할 수 있다. 

서버는 IM 헤더에 사용한 인스턴스 조작의 종류를 명시할 수 있다.

 

델타 인코딩은 전송 시간을 줄일 수 있지만 구현하기가 까다롭다. 

변경이 잦은 페이지에서는 서버는 자신이 제공하는 페이지가 변경되는 매 순간의 사본을 모두 유지하고 있어야 하기 때문이다. 

문서를 제공하는데 걸리는 시간이 줄어드는 대신에, 서버는 문서의 과거 사본을 모두 유지하기 위해 디스크 공간을 더 늘려야 한다. 이는 전송량 감소로 얻는 이득을 금방 무의미하게 만들 것 이다. 

 

 

728x90