HTTP란?
HTTP는 클라이언트와 서버가 서로 통신하는 방법을 표준화하는 TCP/IP 기반 응용 프로그램 계층 통신 프로토콜.
- 컨텐츠가 어떻게 요구되고 인터넷을 통해 전송되는지를 정의한다.
- 애플리케이션 계층 프로토콜(application layer protocol)이란 호스트(클라이언트 및 서버)가 통신하는 방식을 표준화하는 단순한 추상화 계층을 의미한다.
- HTTP 자체는 클라이언트와 서버 간에 요청과 응답을 얻기 위해 TCP/IP에 의존한다. 기본적으로는 TCP 포트 80 이 사용되지만 다른 포트도 사용할 수 있습니다.단, HTTPS는 포트 443을 사용합니다.
HTTP/0.9 - One Liner (1991)
GET이라는 단일 방식을 사용하는 가장 단순한 프로토콜.
- request 형식
GET /index.html
- response 형식
(response body) (connection closed) # 바로 닫힘
특징 정리
- Header X
- GET 만 존재
- response는 HTML만 가능
HTTP/1.0 - 1996
HTML 응답용으로만 설계된HTTP/0.9와는 달리 HTTP/1.0은 이미지, 비디오 파일, 플레인 텍스트 또는 기타 콘텐츠 유형 등 다른 응답 형식에도 대응할 수 있게 되었다.
- 더 많은 메서드(POST 및 HEAD)가 추가
- 요청/응답 형식이 변경
- request
GET / HTTP/1.0 Host: cs.fyi User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) Accept: */*
- response `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 (response body) # 이미지, 비디오, 등등의 여러 콘텐츠 유형 포함 가능
(connection closed)`
- HTTP 헤더가 요청과 응답 모두에 추가
- 응답을 식별하기 위한 상태 코드가 추가
- 문자 집합 지원이 도입되고, 멀티 파트 유형, 인가, 캐싱, 콘텐츠 인코딩 등이 포함.
단점은 연결당 여러 요청을 가질 수 없다는 것
- 즉, 클라이언트는 서버로부터 무언가를 필요로 할 때마다 새로운 TCP 접속을 오픈해야 한다.단일 요구가 충족되면 접속은 닫힌다. 다음 요청은 새로운 접속에 접속해야 합니다.
- 10개의 이미지, 5개의 스타일시트, 5개의 Javascript 파일이 있는 웹페이지를 방문한다고 가정하면, 이 웹페이지에 요청 시 가져와야 하는 항목은 총 20개입니다.서버는 요구가 충족되는 즉시 연결을 종료하기 때문에 20개의 개별 연결로 각 항목이 하나씩 처리된다. 이렇게
- 접속 수가 많으면 새로운 TCP 접속이 필요하기 때문에 3방향 핸드쉐이크에 이은 슬로우 스타트 때문에 퍼포먼스에 악영향을 끼친다.
3방향 핸드쉐이크 (3-way handshake)
simples 형식의 3방향 핸드쉐이크는 모든 TCP 접속이 3방향 핸드쉐이크로 시작된다. 이 핸드쉐이크에서는 클라이언트와 서버가 일련의 패킷을 공유한 후 애플리케이션 데이터를 공유합니다.
- SYN - 클라이언트는 임의의 번호(x 등)를 선택하여 서버에 송신합니다.
- SYN ACK - 서버는 임의의 번호로 구성된 ACK 패킷을 클라이언트에 반송함으로써 요구를 승인합니다.예를 들어, 서버에 의해 픽업된 y와 x+1은 클라이언트가 송신한 번호입니다.
- ACK - 클라이언트는 서버로부터 수신한Y 의 수를 증가시켜, y+1 의 번호로 ACK 패킷을 되돌립니다.
3방향 핸드쉐이크가 완료된 후에 클라이언트와 서버 간의 데이터 공유가 시작될 수 있다. 클라이언트는 마지막 ACK 패킷을 디스패치하면 곧바로 애플리케이션데이터의 송신을 개시할 수 있지만 요구를 만족시키기 위해서 서버는 ACK 패킷의 수신을 대기하게 된다.
HTTP는 상태 비저장 프로토콜이기도 하기에, 서버가 클라이언트에 대한 정보를 유지 관리하지 않으므로 각 요청은 이전 요청과 연결되지 않고 서버가 자체적으로 요청을 수행하는 데 필요한 정보를 가지고 있어야 한다. 따라서 클라이언트가 열어야 하는 많은 수의 연결 외에도 대역폭 사용을 증가시키는 중복 데이터를 와이어로 전송해야 한다.
HTTP/1.1 - 1999
이전 버전으로부터 개선 사항
- 새로운 HTTP 메서드가 추가되어 PUT, PATCH, OPTIONS, DELETE가 도입.
- Hostname Identification In HTTP/1.0 Host 헤더는 필수는 아니지만 HTTP/1.1은 필수이다.
- HTTP/1.0에서는 접속당 요구가1개뿐이었고 요구가 충족되자마자 접속이 종료되어 퍼포먼스 히트나 레이텐시의 문제가 발생했다. HTTP/1.1에는 영구 연결이 도입되어 연결이 기본적으로 닫히지 않고 열린 상태로 유지되어 여러 순차적 요청이 허용 가능하다. 연결을 닫으려면 요청 시 Connection: close 헤더를 사용한다.클라이언트는 이 헤더를 마지막 요청으로 전송하여 연결을 안전하게 닫는다.
- 파이프라인 접속에서는 클라이언트가 같은 접속상의 서버로부터의 응답을 기다리지 않고 서버에 다수의 요구를 송신할 수 있다.
- 서버가 요구를 수신했을 때와 같은 순서로 응답을 송신할 필요가 있는 파이프라인의 서포트도 도입.
- 그러나 클라이언트는 이 시점에서 첫 번째 응답 다운로드가 완료되고 다음 응답 콘텐츠가 시작되는 것을 구별하여 알 수 있어야 한다.
- 이를 위해 Content-Length 헤더의 존재가 필요하다. 이 헤더를 사용하여 응답의 종료 위치를 식별하고 다음 응답을 대기할 수 있다.
- 청크 전송 동적 콘텐츠의 경우 전송이 시작될 때 서버가 실제로 Content-Length를 찾을 수 없는 경우
- 콘텐츠를 조각별로(청크 별로) 전송하기 시작하고 전송될 때 각 청크의 Content-Length를 추가할 수 있다.
- 모든 청크가 전송되면(전체 전송이 완료됨) 빈 청크(Content-Length가 0으로 설정된 청크)를 전송하여 전송 완료된 클라이언트를 식별한다. 청크 전송에 대해 클라이언트에 통지하기 위해 서버는 Transfer-Encoding: chunked 헤더를 포함한다.
- 기본 인증만 있는 HTTP/1.0과 달리 HTTP/1.1에는 다이제스트 및 프록시 인증이 포함되어 있습니다.
- 이 외에 캐싱, 바이트 범위, 문자 집합, 언어 추정, 클라이언트 쿠키, 압축 성능 향상, 새로운 상태 코드 추가 등이 있다.
문제점
- 2000년대 후반부터는 간단한 웹페이지라도 30개 이상의 접속이 필요하게 되면서 지연 시간이 올라감
- 지속적인 접속이 가능했지만 응답이 끝나지 않은 한 개만 접속할 수 있기 때문
- 파이프라인을 도입하여 문제를 해결하려 했지만
- 느리거나 무거운 요청이 들어오면 뒤의 요청을 차단할 수 있다.
- 파이프라인에 고정되면 다음 요청이 실행될 때 까지 기다려야 한다 (Head of Line Blocking)
SPDY - 2009
구글에서 제안한 프로토콜. 지연 시간을 줄이는데 초점을 둔 프로토콜이다. (SPDY는 약자가 아닌 상표)
- 대역폭을 계속 늘리는 테스트에서, 처음에는 네트워크 퍼포먼스가 향상되지만 어느 지점부터 향상되지 않는 포인트가 나타났다.
- 대역폭(bandwidth) : 초당 전송되는 데이터 양 (bit/second)
- 하지만 지연 시간에도 동일한 테스트를 했더니, 지연 시간을 계속 단축할수록 성능이 계속 향상되는 것을 알게되었다. 이것이 SPDY의 퍼포먼스를 향상시키고 레이텐시를 단축하여 네트워크 퍼포먼스를 향상시키는 핵심 아이디어였다.
- 레이턴시(latency) : 데이터가 이동하는데 걸리는 시간 (Milliseconds)
SPDY는 실제로는 HTTP를 대체하려는 것이 아닌. HTTP를 통한 변환 레이어로 어플리케이션레이어에 존재하며 요청을 수정한 후 회선으로 전송하는 역할이였다. 그것은 표준이 되기 시작했지만,
- 2015년 구글에서는 두 개의 경쟁 표준을 가지고 싶지 않았기 때문에 HTTP/2를 만들고 SPDY를 폐지하면서 HTTP에 통합하기로 결정했습니다.
HTTP/2 - 2015
SPDY를 통합시킨 결과이기에 주 목적은 HTTP/2는 콘텐츠의 저지연 전송을 위해 설계되었다.
특징
1. 텍스트가 아닌 바이너리
HTTP/2는 HTTP/1.x를 바이너리 프로토콜로 함으로써 지연 시간이 증가하는 문제를 해결하는 경향이 있다. 바이너리 프로토콜이기 때문에 구문 분석이 더 쉽지만 HTTP/1.x와 달리 더 이상 사람의 눈으로 읽을 수 없다. HTTP/2의 주요 구성 요소는 프레임과 스트림이다.
프레임과 스트림
HTTP 메시지는 하나 이상의 프레임으로 구성된다. (프레임은 이진 데이터 조각이다)
- 메타 데이터에 대한 HEADERS 프레임
- 페이로드에 대한 DATA 프레임
- HTTP/2 사양을 통해 확인할 수 있는 여러 종류의 프레임 (HEADERS, DATA, RST_STREAM, SETTINGS, PRIORITY 등)이 있다.
모든 HTTP/2 요청 및 응답에는 고유한 스트림 ID가 할당되고 프레임으로 분할된다.
프레임의 모음을 스트림이라고 한다.
- 각 프레임에는 해당하는 스트림을 식별하는 스트림 ID와 공통 헤더가 있다.
- 스트림 ID는 고유하다
- 클라이언트에서 시작하는 모든 요청은 홀수 번호를 사용
- 서버에서의 응답은 짝수 번호 스트림 ID를 사용
HEADERS와 DATA 이외에도 여기서 언급할 가치가 있는 다른 프레임 유형은 RST_STREAM이다다
- RST_STREAM은 일부 스트림을 중단하는 데 사용되는 특수 프레임 유형이다.
- 클라이언트는 이 프레임을 보내서 서버에게 이 스트림이 더 이상 필요하지 않다는 것을 알릴 수 있다.
- HTTP/1.1에서 클라이언트가 응답을 받지 않고 서버에게 보내는 유일한 방법은 연결을 닫는 것이었고, 연속적인 요청에 대해 새로운 연결을 열어야 해서 지연이 증가했다. HTTP/2에서는 클라이언트가 RST_STREAM을 사용하여 특정 스트림 수신을 중지할 수 있으며 연결은 여전히 열려 있고 다른 스트림은 계속 작동한다.
2. Multiplexing
HTTP/2는 이제 바이너리 프로토콜이며 요청과 응답에 프레임과 스트림을 사용한다.
TCP 연결이 열리면 모든 스트림이 추가 연결 없이 동기적으로 전송된다. 그리고 서버는 동일한 비동기 방식으로 응답한다.
- 응답에는 순서가 없으며 클라이언트는 할당된 스트림 ID를 사용하여 특정 패킷이 속한 스트림을 식별한다. 이렇게 함으로써 HTTP/1.x에서 발생하는 Head-of-Line Blocking 문제가 해결되며, 클라이언트는 시간이 오래 걸리는 요청을 기다릴 필요 없이 다른 요청이 계속 처리될 수 있다.
HTTP/2는 보내는 헤더를 최적화하기 위해 특별히 목적을 두고 있는 별도의 RFC 중 일부분이다.
- 핵심은 동일한 클라이언트에서 서버에 계속 액세스하는 경우, 헤더에서 중복 데이터가 많이 전송되고 때로는 쿠키가 헤더 크기를 증가시키는 경우가 있어 대역폭 사용량과 지연 시간이 증가하게 된다. 이를 극복하기 위해 HTTP/2는 헤더 압축을 사용한다.
요청과 응답과는 달리 헤더는 gzip 또는 compress 등의 형식으로 압축되지 않지만, 허프만 코드를 사용하여 리터럴 값이 인코딩되며 클라이언트와 서버가 유지하는 헤더 테이블이 있으며, 클라이언트와 서버 모두 재귀적인 헤더(예: 사용자 에이전트 등)를 제외하고 이를 참조하기 위해 헤더 테이블을 사용합니다.
4.서버 푸시
HTTP/2의 중요한 기능 중 하나이다. 클라이언트가 특정 자원을 요청하기 전에 서버가 미리 해당 자원을 클라이언트에게 전송할 수 있다.
- 예시
- 브라우저가 웹 페이지를 로드하면 서버에서 가져와야 하는 원격 콘텐츠를 파싱
- 이후에 클라이언트가 해당 콘텐츠를 요청하기 위해 서버로 요청.
서버 푸시를 사용하면 서버는 클라이언트가 요청할 것으로 예상되는 데이터를 미리 전송함으로써 라운드트립을 줄일 수 있다. PUSH_PROMISE라는 특수한 프레임을 사용하여 클라이언트에게 "이 자원을 보내려고 하고 있으니까, 요청하지 마세요." 라는 메시지를 보낸다. PUSH_PROMISE 프레임은 푸시를 일으킨 스트림과 연결되어 있으며 전송될 자원이 푸시될 스트림 ID를 포함한다.
5.요청 우선순위 지정
클라이언트는 HEADERS 프레임에 우선순위 정보를 포함하여 스트림을 열 수 있습니다. 나중에 클라이언트는 PRIORITY 프레임을 보내어 스트림의 우선순위를 변경할 수 있습니다.
우선순위 정보가 없는 경우, 서버는 비동기적으로 요청을 처리합니다. 스트림에 우선순위가 할당되면 이 정보를 기반으로 서버는 각 요청의 처리에 필요한 자원의 양을 결정합니다.
6. 보안
HTTP/2에서 보안(TLS를 통한)을 필수적으로 해야 하는지에 대한 많은 논의가 있었고, 최종적으로는 필수적으로 하지 않기로 결정되었지만 대부분의 공급업체들은 TLS를 사용할 때만 HTTP/2를 지원할 것이라고 명시했습니다.
- 따라서 HTTP/2는 규격상 암호화가 필수적이지는 않지만, 기본적으로 필수적이라 봐도 무방하다. 또한 TLS 버전 1.2 이상이 사용되어야 하며, 최소한의 키 크기와 일회성 키 등의 요구 사항이 있다.
HTTP/3 - 2022
QUIC 기반의 최신HTTP 버전의 프로토콜이다.
- QUIC : UDP 기반의 전송 계층 프로토콜로 TCP 대체용으로 설계되었다. 지연 시간을 줄이고 성능을 향상시키기 위해 설계된 다중화, 보안, 스트림 기반 프로토콜로 TCP 및 HTTP/2의 후속 버전이다.
1 . Multiplexing
QUIC는 다중화 프로토콜이므로 하나의 연결에서 여러 개의 스트림을 전송할 수 있다.
- HTTP/2와 달리, QUIC는 HTTP에만 한정되지 않는다. 신뢰성 있고 순서대로, 손실 허용 데이터 스트림 전송이 필요한 모든 애플리케이션에서 사용할 수 있다.
2 . 신뢰할 수 없는 데이터그램 (Unreliable Datagram)
QUIC는 신뢰성 없는 데이터그램을 사용하여 데이터를 보낸다.
- QUIC가 데이터가 수신자에게 전달되는 것을 보장하지 않는다는 것을 의미한다.
- 그러나 QUIC는 데이터가 전송된 순서대로 수신자에게 전달된다는 것을 보장한다.
- UDP와 유사 : 데이터를 데이터그램 형식으로 보내고 데이터그램이 수신자에게 전달되지 않을 수 있음을 의미.
이 외에 특징은 Loss Recovery, Connection Migration, Congestion Control 이 있지만 TCP와 유사한 원리를 가지고,
Handshake, 헤더 압축, 보안 은 HTTP/2와 유사한 원리로 작동한다.