HTTP 프로토콜: 인터넷의 초석이자 웹 개발에 필수적인 지식
Daniel Hayes
Full-Stack Engineer · Leapcell

HTTP 프로토콜: 인터넷의 초석이자 웹 개발에 필수적인 지식
인터넷 세계에서 HTTP 프로토콜은 의심할 여지 없이 기본적인 프로토콜이며 웹 개발 분야에서 필수적인 지식입니다. 특히 최신 버전인 HTTP/2는 광범위한 관심을 끌며 기술적인 핫스팟이 되었습니다. 이 기사에서는 HTTP 프로토콜의 역사적 진화와 설계 개념을 자세히 살펴보고 독자들이 이 중요한 기술에 대한 포괄적인 이해를 얻도록 돕습니다.
I. HTTP/0.9: 인터넷 통신의 배아 형태
HTTP는 TCP/IP 프로토콜을 기반으로 하는 애플리케이션 계층 프로토콜입니다. 클라이언트와 서버 간의 통신 형식을 지정하는 데 중점을 두며 데이터 패킷 전송에는 관여하지 않습니다. 기본적으로 포트 80을 사용합니다. 1991년에 릴리스된 HTTP/0.9 버전은 HTTP 프로토콜의 가장 초기 버전입니다. 그 디자인은 매우 간단하며 GET이라는 단 하나의 명령만 있습니다.
GET /index.html
위 명령의 의미는 TCP 연결이 설정된 후 클라이언트가 서버에서 웹 페이지 index.html을 요청한다는 것입니다. 프로토콜에 따라 서버는 HTML 형식의 문자열로만 응답할 수 있으며 다른 형식으로는 응답할 수 없습니다. 예를 들면 다음과 같습니다.
<html> <body>Hello World</body> </html>
서버가 전송을 완료하면 즉시 TCP 연결을 닫습니다. 이 버전은 간단하지만 이후 HTTP 프로토콜 개발의 기반을 마련했으며 클라이언트와 서버 간의 간단한 통신 모드의 확립을 알렸습니다.
II. HTTP/1.0: 기능의 초기 확장
1996년 5월에 HTTP/1.0 버전이 릴리스되었습니다. HTTP/0.9에 비해 내용이 크게 증가하여 인터넷 개발에 중요한 변화를 가져왔습니다.
2.1 소개
-
콘텐츠 형식의 다양화: HTTP/1.0에서는 모든 형식의 콘텐츠를 보낼 수 있습니다. 이를 통해 인터넷은 더 이상 텍스트 전송에 국한되지 않고 이미지, 비디오 및 이진 파일과 같은 다양한 유형의 데이터를 네트워크를 통해 전송할 수 있게 되어 인터넷의 다양화된 개발을 위한 견고한 토대를 마련했습니다.
-
풍부한 대화형 명령: GET 명령 외에도 POST 명령과 HEAD 명령이 도입되었습니다. POST 명령은 사용자 등록 및 로그인 중에 제출된 정보와 같이 데이터를 서버에 제출하는 데 자주 사용됩니다. HEAD 명령은 실제 리소스 콘텐츠를 반환하지 않고 리소스의 메타 정보를 얻는 데 주로 사용됩니다. 이러한 명령의 추가는 브라우저와 서버 간의 상호 작용 방법을 크게 풍부하게 했습니다.
-
요청 및 응답 형식의 변경: 각 통신에서 데이터 부분 외에도 헤더 정보(HTTP 헤더)가 포함되어야 하며, 이는 요청 소스, 클라이언트 유형 및 허용 가능한 데이터 형식과 같은 일부 메타데이터를 설명하는 데 사용됩니다. 또한 상태 코드(status code), 다중 문자 집합 지원, 다중 파트 전송(multi-part type), 권한 부여, 캐시 및 콘텐츠 인코딩과 같은 기능이 추가되었습니다. 상태 코드는 요청에 대한 서버의 처리 결과를 나타내는 데 사용됩니다. 예를 들어 200은 성공적인 요청을 나타내고 404는 리소스를 찾을 수 없음을 나타냅니다. 다중 문자 집합 지원을 통해 인터넷에서 다양한 언어로 콘텐츠를 올바르게 표시할 수 있습니다. 캐시 기능은 반복적인 요청을 줄이고 액세스 속도를 향상시킬 수 있습니다.
2.2 요청 형식
GET / HTTP/1.0
User - Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5)
Accept: */*
HTTP/0.9 버전에 비해 1.0 버전의 요청 형식은 크게 변경되었습니다. 첫 번째 줄은 요청 명령이고 프로토콜 버전(HTTP/1.0)을 끝에 추가해야 합니다. 다음은 클라이언트 상황을 설명하는 데 사용되는 여러 줄의 헤더 정보입니다. User - Agent 필드는 클라이언트의 유형과 버전을 식별하고 Accept 필드는 클라이언트가 수락할 수 있는 데이터 형식을 선언합니다.
2.3 응답 형식
HTTP/1.0 200 OK
Content - Type: text/plain
Content - Length: 137582
Expires: Thu, 05 Dec 1997 16:00:00 GMT
Last - Modified: Wed, 5 August 1996 15:55:28 GMT
Server: Apache 0.84
<html>
<body>Hello World</body>
</html>
서버의 응답 형식은 "헤더 정보 + 빈 줄(\r\n) + 데이터"입니다. 그중 첫 번째 줄은 "프로토콜 버전 + 상태 코드(status code) + 상태 설명"입니다. 상태 코드 200은 성공적인 요청을 나타내고 OK는 상태 설명입니다. Content - Type 필드는 데이터 유형을 나타내고 Content - Length 필드는 데이터 길이를 나타내며 Expires 필드는 리소스 만료 시간을 지정하고 Last - Modified 필드는 리소스의 마지막 수정 시간을 나타내며 Server 필드는 서버의 유형과 버전을 식별합니다.
2.4 Content - Type 필드
HTTP/1.0 버전에서 헤더 정보는 ASCII 코드여야 하고 후속 데이터는 모든 형식일 수 있습니다. 따라서 서버가 응답할 때 Content - Type 필드를 통해 클라이언트에 데이터 형식을 알려야 합니다. Content - Type 필드의 일반적인 값은 다음과 같습니다.
- 텍스트 유형: text/plain(일반 텍스트), text/html(HTML 문서), text/css(CSS 스타일 시트).
- 이미지 유형: image/jpeg(JPEG 이미지), image/png(PNG 이미지), image/svg + xml(SVG 벡터 그래픽).
- 오디오 및 비디오 유형: audio/mp4(MP4 오디오), video/mp4(MP4 비디오).
- 응용 프로그램 유형: application/javascript(JavaScript 스크립트), application/pdf(PDF 문서), application/zip(ZIP 압축 파일), application/atom + xml(Atom XML 문서).
이러한 데이터 유형을 총칭하여 MIME 유형이라고 합니다. 각 값에는 슬래시로 구분된 기본 유형과 보조 유형이 포함됩니다. 미리 정의된 유형 외에도 제조업체는 application/vnd.debian.binary - package
와 같이 사용자 지정 유형을 정의할 수도 있습니다. 이는 전송된 데이터가 Debian 시스템의 이진 데이터 패키지임을 나타냅니다. MIME 유형은 세미콜론을 사용하여 끝에 매개변수를 추가할 수도 있습니다. 예를 들어 Content - Type: text/html; charset=utf - 8
은 전송된 데이터가 웹 페이지이고 인코딩이 UTF - 8임을 나타냅니다. 클라이언트가 요청할 때 Accept 필드를 사용하여 클라이언트가 수락할 수 있는 데이터 형식을 선언할 수 있습니다. 예를 들어 Accept: */*
는 클라이언트가 모든 형식의 데이터를 수락할 수 있음을 나타냅니다. MIME 유형은 HTTP 프로토콜뿐만 아니라 다른 분야에서도 널리 사용됩니다. 예를 들어 HTML 웹 페이지에서 페이지의 인코딩 및 콘텐츠 유형은 <meta http - equiv="Content - Type" content="text/html; charset=UTF - 8" />
또는 <meta charset="utf - 8" />
를 통해 지정할 수 있습니다.
2.5 Content - Encoding 필드
전송되는 데이터는 모든 형식이 될 수 있으므로 전송 효율성을 높이기 위해 전송 전에 데이터를 압축할 수 있습니다. Content - Encoding 필드는 데이터의 압축 방법을 나타내는 데 사용됩니다. 일반적인 값은 gzip
, compress
, deflate
입니다. 클라이언트가 요청할 때 Accept - Encoding 필드를 사용하여 클라이언트가 수락할 수 있는 압축 방법을 나타냅니다. 예를 들어 Accept - Encoding: gzip, deflate
입니다.
2.6 단점
HTTP/1.0 버전의 주요 단점은 각 TCP 연결이 하나의 요청만 보낼 수 있다는 것입니다. 데이터가 전송된 후 연결이 닫힙니다. 다른 리소스를 요청해야 하는 경우 새 연결을 설정해야 합니다. 새 TCP 연결을 설정하는 데 드는 비용은 클라이언트와 서버가 3방향 핸드셰이크를 수행해야 하고 초기 전송 속도가 느리기 때문에(느린 시작) 비교적 높으므로 HTTP 1.0 버전의 성능이 저하됩니다. 웹 페이지에 점점 더 많은 외부 리소스가 로드됨에 따라 이 문제가 더욱 두드러졌습니다. 이 문제를 해결하기 위해 일부 브라우저는 요청에서 비표준 Connection 필드를 사용했습니다.
Connection: keep - alive
이 필드는 서버가 TCP 연결을 닫지 않도록 요구하여 다른 요청을 재사용할 수 있도록 합니다. 서버가 이 필드로 응답하는 경우 클라이언트 또는 서버가 연결을 적극적으로 닫을 때까지 재사용 가능한 TCP 연결을 설정할 수 있습니다. 그러나 이것은 표준 필드가 아니며 구현에 따라 동작이 다를 수 있으므로 근본적인 해결책은 아닙니다.
III. HTTP/1.1: 널리 사용되는 클래식 버전
1997년 1월에 HTTP/1.1 버전이 릴리스되었는데, 1.0 버전보다 불과 반년 후였습니다. HTTP 프로토콜을 더욱 개선했으며 현재도 널리 사용되는 버전이 되었습니다.
3.1 영구 연결
HTTP/1.1 버전의 가장 큰 변화는 영구 연결의 도입입니다. 즉, TCP 연결은 기본적으로 닫히지 않으며 Connection: keep - alive
를 선언할 필요 없이 여러 요청에서 재사용할 수 있습니다. 클라이언트와 서버는 상대방이 한동안 비활성 상태인 것을 발견하면 연결을 적극적으로 닫을 수 있습니다. 그러나 표준적인 방법은 클라이언트가 마지막 요청에서 Connection: close
를 보내 서버에 TCP 연결을 닫도록 명시적으로 요청하는 것입니다. 현재 대부분의 브라우저는 동일한 도메인 이름에 대해 6개의 영구 연결을 설정할 수 있으므로 HTTP 프로토콜의 효율성이 크게 향상됩니다.
3.2 파이프라이닝
HTTP/1.1 버전에서는 파이프라이닝 메커니즘도 도입했습니다. 동일한 TCP 연결에서 클라이언트는 여러 요청을 동시에 보낼 수 있습니다. 예를 들어 클라이언트가 두 개의 리소스를 요청해야 하는 경우 이전 접근 방식은 동일한 TCP 연결에서 먼저 요청 A를 보내고 서버의 응답을 기다린 다음 응답을 받은 후 요청 B를 보내는 것이었습니다. 파이프라이닝 메커니즘을 사용하면 브라우저에서 요청 A와 요청 B를 동시에 보낼 수 있습니다. 서버가 여전히 요청 A에 순서대로 먼저 응답한 다음 완료 후 요청 B에 응답하지만 이 방법은 HTTP 프로토콜의 효율성을 더욱 향상시킵니다.
3.3 Content - Length 필드
HTTP/1.1 버전에서는 TCP 연결이 여러 응답을 전송할 수 있습니다. 따라서 데이터 패킷이 속한 응답을 구별하는 메커니즘이 필요합니다. Content - Length 필드의 기능은 이 응답에서 데이터 길이를 선언하는 것입니다. 예를 들면 다음과 같습니다.
Content - Length: 3495
이 코드 줄은 브라우저에 이 응답의 길이가 3495바이트이고 후속 바이트가 다음 응답에 속한다는 것을 알려줍니다. 1.0 버전에서는 브라우저가 서버가 TCP 연결을 닫았음을 감지했을 때 모든 데이터 패킷이 수신되었음을 알았기 때문에 Content - Length 필드가 필요하지 않았습니다. 1.1 버전에서는 TCP 연결을 재사용할 수 있으므로 다른 응답을 구별하기 위해 데이터 길이를 명확히 해야 합니다.
3.4 Chunked Transfer Encoding
Content - Length 필드를 사용하기 위한 전제 조건은 서버가 응답을 보내기 전에 응답 데이터의 길이를 알아야 한다는 것입니다. 시간이 오래 걸리는 동적 작업의 경우 서버가 모든 작업이 완료될 때까지 기다려야 데이터를 보낼 수 있으므로 효율성이 떨어집니다. 이 문제를 해결하기 위해 HTTP/1.1 버전에서는 Content - Length 필드를 사용하지 않고 대신 "청크 분할 전송 인코딩"을 사용할 수 있다고 규정하고 있습니다. 요청 또는 응답 헤더에 Transfer - Encoding 필드가 있는 한 응답이 결정되지 않은 수의 데이터 청크로 구성됨을 나타냅니다. 예를 들면 다음과 같습니다.
Transfer - Encoding: chunked
비어 있지 않은 각 데이터 청크 앞에는 이 청크의 길이를 나타내는 16진수 값이 있습니다. 마지막으로 크기가 0인 청크는 이 응답의 데이터가 완전히 전송되었음을 나타냅니다. 다음은 예입니다.
HTTP/1.1 200 OK
Content - Type: text/plain
Transfer - Encoding: chunked
25
This is the data in the first chunk
1C
and this is the second one
3
con
8
sequence
0
이 방법을 사용하면 서버가 생성되는 즉시 데이터를 보낼 수 있으므로 "버퍼 모드"를 "스트림 모드"로 대체하여 데이터 전송 효율성을 향상시킬 수 있습니다.
3.5 기타 기능
HTTP/1.1 버전에서는 PUT(리소스를 업데이트하는 데 사용됨), PATCH(리소스를 부분적으로 업데이트하는 데 사용됨), HEAD(GET과 유사하지만 리소스 콘텐츠가 아닌 헤더 정보만 반환함), OPTIONS(서버에서 지원하는 요청 방법과 같은 정보를 얻는 데 사용됨), DELETE(리소스를 삭제하는 데 사용됨)와 같은 많은 동사 방법도 추가했습니다. 또한 클라이언트 측 요청 헤더에 서버의 도메인 이름을 지정하는 데 사용되는 Host 필드가 추가되었습니다. 예를 들면 다음과 같습니다.
Host: www.example.com
Host 필드를 사용하면 동일한 서버에서 다른 웹사이트로 요청을 보낼 수 있으므로 가상 호스팅의 부상을 위한 기반을 마련할 수 있습니다. Host 필드를 통해 서버는 다른 도메인 이름에 따라 다른 서비스를 제공하여 리소스 공유 및 격리를 달성할 수 있습니다.
3.6 단점
HTTP/1.1 버전에서는 TCP 연결을 재사용할 수 있지만 동일한 TCP 연결에서 모든 데이터 통신이 순서대로 수행됩니다. 서버는 하나의 응답을 완료한 후에만 다음 응답을 처리합니다. 이전 응답이 특히 느린 경우 많은 요청이 대기열에 추가되어 대기하게 되는데, 이를 "Head - of - line blocking"이라고 합니다. 이 문제를 피하기 위해 현재 두 가지 방법만 있습니다. 하나는 요청 수를 줄이는 것이고 다른 하나는 여러 영구 연결을 동시에 여는 것입니다. 이로 인해 스크립트 및 스타일 시트 병합, CSS 코드에 이미지 포함, 도메인 샤딩과 같은 많은 웹 페이지 최적화 기술이 등장했습니다. 그러나 HTTP 프로토콜이 더 잘 설계되었다면 이러한 추가 노력을 피할 수 있었습니다.
IV. SPDY 프로토콜: HTTP/2의 선구자
2009년에 Google은 자체 개발한 SPDY 프로토콜을 공개적으로 발표했는데, 주로 HTTP/1.1의 낮은 효율성 문제를 해결하는 것을 목표로 했습니다. Chrome 브라우저에서 실현 가능한 것으로 입증된 후 SPDY 프로토콜은 HTTP/2의 기반으로 사용되었으며 주요 기능은 HTTP/2에서 상속되었습니다. SPDY 프로토콜은 헤더 정보 압축 및 멀티플렉싱과 같은 HTTP 프로토콜 최적화를 통해 데이터 전송 효율성을 향상시켜 HTTP/2 개발에 귀중한 경험과 기술적 기반을 제공했습니다.
V. HTTP/2: 효율적인 차세대 프로토콜
2015년에 HTTP/2가 릴리스되었습니다. 표준 위원회에서 더 이상 하위 버전을 릴리스할 계획이 없기 때문에 HTTP/2.0이라고 부르지 않습니다. 다음 새로운 버전은 HTTP/3가 될 것입니다. HTTP/2는 HTTP 프로토콜 개발 역사에서 큰 의미를 가지며 일련의 놀라운 개선 사항을 가져왔습니다.
5.1 이진 프로토콜
HTTP/1.1 버전의 헤더 정보는 텍스트(ASCII 인코딩)이고 데이터 본문은 텍스트 또는 이진수일 수 있습니다. 그러나 HTTP/2는 완전히 이진 프로토콜입니다. 헤더 정보와 데이터 본문은 모두 이진수이며 헤더 프레임과 데이터 프레임을 포함하여 총칭하여 "프레임"이라고 합니다. 이진 프로토콜의 장점은 추가 프레임을 정의할 수 있다는 것입니다. HTTP/2는 후속 고급 애플리케이션을 위한 좋은 기반을 마련하여 거의 10개의 프레임을 정의했습니다. 이러한 기능을 텍스트를 사용하여 구현하면 데이터를 구문 분석하는 것이 매우 번거롭지만 이진 구문 분석은 훨씬 더 편리합니다. 이진 프로토콜은 데이터를 보다 효율적으로 전송하고 처리하여 프로토콜의 성능과 유연성을 향상시킬 수 있습니다.
5.2 멀티플렉싱
HTTP/2는 TCP 연결을 재사용합니다. 하나의 연결에서 클라이언트와 브라우저는 모두 여러 요청 또는 응답을 동시에 보낼 수 있으며 순서대로 하나씩 서로 대응할 필요가 없으므로 "Head - of - line blocking"을 피할 수 있습니다. 예를 들어 TCP 연결에서 서버는 요청 A와 요청 B를 동시에 받습니다. 따라서 먼저 요청 A에 응답합니다. 처리 프로세스가 매우 오래 걸리는 것을 발견하면 처리된 요청 A의 일부를 보내고 요청 B에 응답합니다. 완료 후 요청 A의 나머지 부분을 보냅니다. 이 양방향 실시간 통신을 멀티플렉싱이라고 합니다. 멀티플렉싱 기술을 통해 HTTP/2는 동일한 연결에서 여러 요청과 응답을 동시에 처리할 수 있으므로 전송 효율성이 크게 향상됩니다.
5.3 데이터 스트림
HTTP/2의 데이터 패킷은 순서 없이 전송되므로 동일한 연결의 연속 데이터 패킷이 다른 응답에 속할 수 있습니다. 따라서 데이터 패킷에 마크를 표시하여 어떤 응답에 속하는지 나타내야 합니다. HTTP/2는 각 요청 또는 응답의 모든 데이터 패킷을 데이터 스트림이라고 합니다. 각 데이터 스트림에는 고유한 번호가 있습니다. 데이터 패킷을 보낼 때 속한 데이터 스트림을 구별하기 위해 데이터 스트림 ID를 표시해야 합니다. 또한 클라이언트에서 보낸 데이터 스트림에는 홀수 ID가 있고 서버에서 보낸 데이터 스트림에는 짝수 ID가 있다고 규정되어 있습니다. 데이터 스트림이 중간에 전송되는 동안 클라이언트와 서버는 모두 신호(RST_STREAM 프레임)를 보내 이 데이터 스트림을 취소할 수 있습니다. HTTP/1.1 버전에서는 TCP 연결을 닫는 것이 데이터 스트림을 취소하는 유일한 방법입니다. 그러나 HTTP/2에서는 TCP 연결이 여전히 열려 있고 다른 요청에서 사용할 수 있도록 특정 요청을 취소할 수 있습니다. 클라이언트는 데이터 스트림의 우선 순위를 지정할 수도 있습니다. 우선 순위가 높을수록 서버는 더 빨리 응답합니다. 데이터 스트림의 개념과 관련 메커니즘을 통해 HTTP/2는 보다 유연하고 효율적인 데이터 전송 및 관리를 달성합니다.
5.4 헤더 압축
HTTP 프로토콜은 상태 비저장이므로 모든 정보를 각 요청에 첨부해야 합니다. 따라서 요청에 많은 필드가 반복됩니다(예: Cookie 및 User - Agent). 동일한 콘텐츠를 각 요청에 첨부해야 하므로 많은 대역폭이 낭비되고 속도에 영향을 미칩니다. HTTP/2는 헤더 압축 메커니즘을 도입하여 이를 최적화했습니다. 한편으로 헤더 정보는 gzip 또는 compress를 사용하여 압축한 후 보냅니다. 다른 한편으로 클라이언트와 서버는 모두 헤더 정보 테이블을 유지합니다. 모든 필드는 이 테이블에 저장되어 인덱스 번호를 생성합니다. 앞으로는 동일한 필드가 다시 전송되지 않고 인덱스 번호만 전송되므로 속도가 향상됩니다. 헤더 압축 메커니즘은 데이터 전송량을 효과적으로 줄이고 전송 효율성을 향상시킵니다.
5.5 서버 푸시
HTTP/2를 사용하면 서버에서 요청 없이 클라이언트에 리소스를 적극적으로 보낼 수 있는데, 이를 서버 푸시라고 합니다. 일반적인 시나리오는 클라이언트가 많은 정적 리소스가 포함된 웹 페이지를 요청하는 경우입니다. 정상적인 상황에서는 클라이언트가 웹 페이지를 받고 HTML 소스 코드를 구문 분석하고 정적 리소스를 발견한 다음 정적 리소스에 대한 요청을 보내야 합니다. 그러나 서버는 클라이언트가 웹 페이지를 요청한 후 정적 리소스를 요청할 가능성이 높다고 예상할 수 있으므로 웹 페이지와 함께 이러한 정적 리소스를 클라이언트에 적극적으로 보냅니다. 서버 푸시 기술은 클라이언트 요청 수를 줄이고 사용자 경험을 향상시킵니다.
HTTP 프로토콜의 개발 역사는 지속적인 진화와 최적화의 과정입니다. 처음에는 간단한 HTTP/0.9에서 기능이 풍부한 HTTP/1.1로, 다음에는 효율적인 HTTP/2로 각 버전은 이전 버전의 문제를 해결하고 성능과 기능을 향상시켰습니다. 기술이 지속적으로 발전함에 따라 미래의 HTTP/3도 기대할 만하며 인터넷 통신 기술의 발전을 계속 주도할 것입니다.
Leapcell: 웹 호스팅, 비동기 작업 및 Redis를 위한 차세대 서버리스 플랫폼
마지막으로 웹 서비스 배포에 가장 적합한 플랫폼인 **Leapcell**을 추천하고 싶습니다.
1. 다국어 지원
- JavaScript, Python, Go 또는 Rust로 개발합니다.
2. 무제한 프로젝트를 무료로 배포
- 사용량에 대해서만 지불합니다. 요청도 없고 요금도 없습니다.
3. 타의 추종을 불허하는 비용 효율성
- 유휴 요금 없이 사용한 만큼 지불합니다.
- 예: $25는 평균 응답 시간이 60ms인 694만 건의 요청을 지원합니다.
4. 간소화된 개발자 경험
- 간편한 설정을 위한 직관적인 UI.
- 완전 자동화된 CI/CD 파이프라인 및 GitOps 통합.
- 실행 가능한 통찰력을 위한 실시간 메트릭 및 로깅.
5. 간편한 확장성 및 고성능
- 고도의 동시성을 쉽게 처리하기 위한 자동 확장.
- 운영 오버헤드가 전혀 없습니다. 빌드에만 집중하십시오.
Leapcell Twitter: https://x.com/LeapcellHQ