해당 글은 그림으로 배우는 HTTP & Network basic을 읽고 정리한 글입니다.
웹은 HTTP로 나타낸다.
웹 브라우저 주소란에 URL을 입력했을 때 어떻게 웹 페이지가 보여질까요? 웹 브라우저는 웹 브라우저 주소 입력란에 지정된 URL에 의지해서 웹 서버로부터 리소스라고 불리는 파일등의 정보를 얻고 있는 것 입니다.
이 때, 서버에 의뢰를 하는 웹 브라우저는 클라이언트, 요청을 보내는 곳은 웹 서버라고 합니다.
이렇게 클라이언트와 서버까지 일련의 흐름을 결정하고 있는 것은 웹에서 HTTP(Hyper Text Transfer Protocol)이라고 불리는 프로토콜입니다.
프로토콜은 일종의 약속입니다.
네트워크의 기본은 TCP/IP
이 포스팅에서는 주로 HTTP를 다루므로, TCP/IP는 간략하게 넘어가겠습니다. 더욱 알고 싶으시면 다른 자료를 더 찾아보시는 것을 추천드립니다.
HTTP를 이해하기 위해서는 TCP/IP 프로토콜에 대해 어느 정도 알고 있어야 합니다. 인터넷을 포함해서 일반적으로 사용하고 있는 네트워크는 TCP/IP라는 프로토콜에서 움직이고 있습니다. HTTP는 그 중 하나입니다.
프로토콜은 서로 통신하기 위한 약속입니다. 그 중에서 인터넷과 관련해서 케이블 규격, IP 주소 지정 방법, 떨어진 상대를 찾기 위한 방법과 그 곳에 도달하는 순서, 웹을 표시하기 위한 순서 등등 인터넷과 관련된 프로토콜을 모아둔 것을 TCP/IP
프로토콜이라고 합니다.
TCP/IP
는 계층화(layer)로 되어있는데, 애플리케이션, 트랜스포트, 네트워크, 링크 계층 이렇게 4개의 계층으로 되어있습니다.
계층화에는 여러 장점이 있는데, 그 중 하나는 각각의 계층이 변경이 되어도 다른 계층은 신경쓰지 않아도 된다는 분리의 이점이 있습니다. 그래서 각 계층은 다른 계층에 영향받지 않고 자유롭게 설계할 수 있습니다.
애플리케이션 계층
애플리케이션에서 사용하는 통신의 움직임을 결정하는 곳 입니다.
FTP
(파일 전송 프로토콜), DNS
(도메인 네임 스페이스) 등이 애플리케이션의 한 가지 입니다. HTTP
도 이 계층에 포함됩니다.
트랜스포트 계층
트랜스포트 계층은 애플리케이션 계층에서 네트워크로 접속되어 있는 2대의 컴퓨터 사이의 데이터 흐름을 제공합니다. 트랜스포트 계층에서는 서로 다른 성질을 가진 TCP(Transmission Control Protocol)
와 UDP(User Data Protocol)
로 두 가지 프로토콜이 있습니다.
네트워크 계층(혹은 인터넷 계층)
네트워크 계층은 네트워크 상에서 패킷의 이동을 다룹니다. 패킷이란 전송하는 데이터의 최소 단위입니다. 이 계층에서는 어떠한 경로를 거쳐 상대의 컴퓨터까지 패킷을 보낼지를 결정하기도 합니다.
인터넷의 경우라면 상대 컴퓨터에 도달하는 동안에 경로를 지정할 때 하나의 길을 결정하는 것이 네트워크 계층의 역할입니다.
링크 계층 (혹은 데이터 링크 계층, 네트워크 인터페이스 계층)
네트워크에 접속하는 하드웨어적인 면만 다룹니다. 운영체제가 하드웨어를 제어하기 때문에 디바이스 드라이버랑 네트워크 인터페이스 카드를 포함합니다.
그리고 케이블 등과 같이 물리적으로 보이는 부분(커텍트 등을 포함한 여러 가지 전송 매체)도 포함합니다. 하드웨어, 물리적인 부분은 전부 링크 계층의 역할입니다.
HTTP와 관계가 깊은 프로토콜은 IP, TCP, DNS
패킷을 전달하기 위한 IP
요기서 IP는 Internet Protocol입니다. 우리가 흔히 말하는 IP 주소와는 다릅니다. IP의 역할은 개개의 패킷을 상대방에게 전달하는 것입니다. IP는 ARP(Address Resolution Protocol)
을 통해서 MAC 주소를 사용해서 목적지까지 찾아갑니다.
신뢰성을 담당하는 TCP
TCP
는 계층으로 말하면 트랜스포트 층에 해당하는데, 신뢰성 있는 바이트 스트림 서비스를 제공합니다.
스트림 서비스는 용량이 큰 데이터를 보내기 쉽게 TCP 세그먼트
라고 불리는 단위 패킷으로 작게 분해하여 관리하는 것을 말합니다.
신뢰성 있는 서비스는 Three way handshaking
이라는 방법을 이용해서 패킷을 보내고 나서 상대방에게 잘 보내졌는지 확인하는 방법을 이용해서 통신의 신뢰성을 보증합니다.
그러니까 TCP는 대용량의 데이터를 보내기 쉽게 작게 분해하고, 정확하게 도착했는지 확인하는 역할을 하고 있습니다.
이름 해결을 담당하는 DNS
DNS는 HTTP와 같이 응용(애플리케이션) 계층에서 도메인 이름과 IP 주소 이름 확인을 제공합니다.
다시 HTTP
해당 장은 대부분 HTTP 1.1 버전을 기준으로 설명합니다.
아래에서 HTTP의 기본적인 내용들에 대해서 살펴보겠습니다.
1. HTTP는 클라이언트와 서버 간에 통신을 한다.
TCP/IP에 있는 다른 많은 프로토콜과 마찬가지로 HTTP도 클라이언트와 서버 간에 통신을 합니다. 텍스트와 이미지 등과 같은 리소스를 필요하다고 요구하는 쪽이 클라이언트가 되고, 이러한 리소스를 제공하는 쪽이 서버가 됩니다.
2. Request(요청)과 Response(응답)을 교환해서 성립한다.
반드시 클라이언트에서 요청을 보내고, 결과가 서버에서 응답으로 되돌아옵니다. 반드시 클라이언트 측으로부터 통신이 시작됩니다.
3. HTTP는 상태를 유지하지 않는 프로토콜이다.
HTTP는 상태를 유지하지 않는 스테이트리스(stateless) 프로토콜입니다. 응답과 요청을 주고 받는 동안에 상태를 관리하지 않습니다.
클라이언트: 전에 뭘 보냈었지? 서버: 전에 뭘 보냈었지?
그래서 HTTP에서 요청을 보낼 때 마다 새로운 응답이 생성됩니다. 과거의 데이터를 전혀 가지고 있지 않습니다. HTTP는 많은 데이터를 매우 빠르고 확실하게 처리하는 범위성(scalability)를 확보하기 위해서 이와 같이 간단하게 설계되어 있습니다.
근데 웹이 진화함에 따라서, stateless
특성으로는 처리하기 어려운 일이 많아졌습니다.
로그인 정보를 유지를 해야하는 경우가 많은데, HTTP 프로토콜은 상태를 유지하지 않기 때문에, 이 대신에 쿠키라는 기술이 도입이 되어 통신에서도 계속 상태를 관리할 수 있게 되었습니다.
4. 요청 URI로 리소스를 식별한다.
URI과 URL은 다른 의미이지만 요기에서는 동일하게 생각해도 무관합니다.
HTTP는 URI를 사용하여 인터넷 상의 리소스를 지정합니다. 이 URI가 있는 덕분에 인터넷 상의 어떤 장소에 있는 리소스도 호출할 수 있습니다.
아래 주소들은 실제 주소는 아닙니다.
- http://www.helloworld.com/index.html
- http://www.hackr.jp/
- http://www.dog.com/photo/dog1.jpeg
위와 같이 HTTP는 URI라고 불리는 형식으로 모든 요청에 URI를 포함해야 합니다.
5. 서버에 임무를 부여하는 HTTP 메소드들
해당 메소드들은 HTTP 1.1 버전에서 사용할 수 있습니다.
GET
: 리소스 획득POST
: 엔티티 전송PUT
: 파일 전송HEAD
: 메세지 헤더 획득DELETE
: 파일 삭제OPTIONS
: 제공하고 있는 메소드의 문의TRACE
: 경로 조사CONNECT
: 프록시에 터널링 요구
6. 지속 연결과 파이프라인화로 접속량을 절약
HTTP 초기 버전에는 HTTP 통신을 한 번 할 때마다 TCP에 의해 연결과 종료를 할 필요가 있었습니다. 초기에는 작은 사이즈의 텍스트를 보내는 정도여서 상관없었지만, 웹이 발전함에 따라 다량의 이미지, 텍스트, 컨텐츠를 보내고 있기 때문에 한 번 요청을 보낼 때 TCP 연결을 하고, 종료하고 하는 작업이 엄청난 통신량으로 다가왔습니다.
그래서 HTTP/1.1과 일부 HTTP/1.0에서는 TCP 연결 문제를 해결하기 위해서 지속 연결이라는 방법을 고안했습니다. 지속 연결의 특징은 어느 한 쪽이 명시적으로 연결을 종료하지 않으면 TCP 연결을 계속 유지하는 방식입니다.
지속 연결이 가능해짐에 따라 클라이언트와 서버의 파이프라인화가 가능해졌습니다. 파이프라인화에 의해서 이전에는 요청 이후에 응답이 올 때까지 기다린 뒤에 다시 요청을 보내던 것을 응답을 기다리지 않고 요청을 계속해서 보낼 수 있습니다.
HTTP/0.9, 일부 HTTP/1.0(개별 연결) < 일부 HTTP/1.0, HTTP/1.1 (지속 연결) < HTTP/1.1 파이프라인화
개별 연결보다는 지속 연결이 요청 완료가 빠르고, 지속 연결보다는 파이프라인화 쪽이 빠릅니다. 이 차이는 요청 수가 늘어날 수록 현저하게 차이가 납니다.
7. 쿠키를 사용한 상태 관리
HTTP는 스테이트리스(stateless) 프로토콜 이므로, 요청과 응답의 상태를 관리하지 않습니다. 그래서 과거의 상태를 근거로 무언가를 처리하는 것은 불가능합니다.
예를 들어 인증이 필요한 웹 사이트에서 상태 관리를 하지 않는다면, 인증을 마친 상태를 기억하지 못하기 때문에 새로운 페이지로 이동할 때마다 인증을 다시 한다거나, 요청에 매개 변수나 추가적인 정보를 붙여서 지속적으로 로그인 상태를 확인해야 하는 상황이 발생합니다.
스테이트리스가 위 처럼 단점만 있는 건 아닙니다. 서버의 CPU나 메모리 같은 리소스의 소비를 억제할 수 있습니다. 그리고 단순하게 설계되었기 때문에 좀 더 다양한 곳에서 사용할 수 있다는 장점이 있습니다.
하지만 스테이트리스의 단점을 보완하기 위해서 쿠키(cookie) 시스템이 도입되었습니다. 쿠키는 서버에서 응답으로 보내진 Set-Cookie
라는 헤더 필드에 의해 쿠키를 클라이언트에 보존하게 됩니다. 다음 번에 클라이언트가 같은 서버로 요청을 보내면 자동적으로 쿠키를 싣어서 송신합니다. 이렇게 서버는 클라이언트가 자동적으로 같이 보낸 쿠키를 통해서 상태를 관리하고 체크해서 그에 맞는 응답을 보내줄 수 있습니다.
결과를 전달하는 HTTP 상태 코드
서버에서 클라이언트에게 요청에 대한 결과가 어떻게 되었는지 알려주는 것이 상태 코드 입니다.
상태 코드는 200 OK
처럼 3자리 숫자와 상태 설명으로 이루어 집니다.
3자리 숫자에서 첫번째 자리는 응답 클래스를 나타내는데, 응답 클래스에는 5가지가 있습니다.
- 1xx (
Informational
): 요청을 받아들여 처리중 - 2xx (
Success
): 요청을 정상적으로 처리했음 - 3xx (
Redirection
): 요청을 완료하기 위해서 추가 동작이 필요 - 4xx (
Client Error
): 서버는 요청 이해 불가능 - 5xx (
Server Error
): 서버는 요청 처리 실패
HTTP 상태 코드는 RFC2616
에 실려있는 것만 해도 40종류가 있고, RFC6585
등과 같은 확장을 포함하면 60종류 이상이 있습니다. 요기에서는 대표적인 14가지 상태 코드를 알아보겠습니다.
상태 코드에 대한 내용을 클라이언트와 서버의 대화라고 느껴보세요.
200 OK
서버: 요청을 정상 처리했어요!
클라이언트가 보낸 요청을 서버가 정상 처리했음을 나타냅니다.
204 No Content
서버: 요청은 성공했는데, 반환으로 돌려줄 리소스가 없어요.
클라이언트가 서버에 정보를 보내는 것으로 만족하고 클라이언트에 대해서 새로운 정보를 보낼 필요가 없는 경우에 사용됩니다.
206 Partial Content
클라이언트: 반환값중에 일부값만 받고 싶어요! 서버: 자, 요기 네가 원한 일부야!
클라이언트가 Content-Range
로 범위를 지정하면 서버는 해당하는 범위의 리소스를 엔티티에 포함시켜 보내게 됩니다.
301 Moved Permanently
서버: 클라이언트! 네가 준 그 URI는 새것이 아닌데, 북마크라던가 변경하지 않을래? 클라이언트: 아, 알겠어 북마크를 변경할 필요가 있구나.
이 응답은 요청된 리소스에 새로운 URI가 부여되어 있기 때문에 이후에는 그 리소스를 참조하는 URI를 사용해야 한다는 것을 나타냅니다.
302 Found
서버: URI는 잠시 다른 장소에 가 있긴한데, 우선 너한테 줄게!
302는 요청된 리소스에는 새로운 URI가 할당되어 있어서 그 URI를 참조해 주길 바란다는 의미를 가지고 있습니다.
303 See Other
서버: 클라이언트 네가 준 URI가 새것으로 바꼈으니까 그 쪽으로 갈래?
303은 요청에 대한 리소스는 다른 URI에 있기 때문에 GET
메소드를 사용해서 얻어야 한다는 것을 나타냅니다.
304 Not Modified
서버: 리소스는 있는데 조건이 맞질 않아...
304는 클라이언트가 조건부 요청을 했을 때, 리소스에 대한 액세스는 허락하는데 조건이 맞지 않을 때 반환하는 상태입니다. 304일 때는 응답 바디에 아무것도 포함되지 않아야 합니다.
307 Temporary Redirect
307은 302(Found)와 같은 의미입니다.
다른 점은 302는 POST로 부터 GET 치환이 금지되어 있는데도 불구하고 구현상 그와 같이 되어 있지는 않습니다. 307에서는 브라우저 사양에 따라 POST에서 GET으로 치환을 하지 않습니다.
400 Bad Request
서버: 이 요청 뭐야.. 뭔가 잘못 됐는데?
요청이 잘못되었음을 나타내는 상태 코드입니다. 이 에러가 발생했을 때는 클라이언트의 요청 내용을 재검토할 필요가 있습니다.
401 Unauthorized
서버: 이 요청은 인증이 필요해!..
401 응답은 송신한 요청에 HTTP 인증 정보가 필요하 다는 것을 의미합니다.
403 Forbidden
서버: 이 리소스에는 접근하지 못해! 클라이언트!
403 상태 코드는 요청된 리소스에는 클라이언트가 접근하지 못함을 의미합니다. 서버 측은 거부의 이유를 분명히 할 필요가 있는데, 이유를 명확하게 하는 경우에는 엔티티 바디에 기재해서 클라이언트에 전해줍니다.
404 Not Found
서버: 클라이언트, 네가 요청한건 이 곳에 없어..
클라이언트가 요청한 리소스는 서버에 없다는 것을 의미합니다.
500 Internal Server Error
서버: 뭔가 우리 리소스에 문제가 생긴 것 같아.. 클라이언트..
서버에서 요청을 처리하는 도중에 에러가 발생했음을 나타냅니다.
503 Service Unavailable
서버: 미안 클라이언트... 나 지금 너무 바빠
서버가 일시적으로 과부화가 걸렸거나, 점검중이라는 것을 의미합니다.
이 때는 Retry-After
헤더 필드에 클라이언트에게 명시해주는 것이 좋습니다.
HTTP 메세지 헤더
모든 HTTP 요청과 응답에는 반드시 메세지 헤더가 포함되어 있습니다. 메세지 헤더에는 보통 요청이나 응답을 처리하기 위한 정보가 들어가 있습니다.
아래에는 HTTP/1.1과 일반적으로 자주 사용되고 있는 부분에 대해서 다룹니다.
헤더 필드
헤더 필드에는 중요한 정보를 전달합니다.
헤더 필드는 field name: field value
처럼 필드 명과 필드 값으로 구성되어 있고 콜론으로 구분됩니다.
만약 Content-Type:text/html
과 같은 헤더 필드가 있으면 Content-Type
이 필드 명이고, text/html
은 필드 값 입니다.
그리고 헤더 값은 Keep-Alive:timeout=15,max=10
과 같이 여러 개의 값(예시는 timeout과 max 이렇게 둘)을 가질 수 있습니다.
여러 종류의 헤더 필드
HTTP 헤더 필드에는 용도에 따라서 4가지로 분류됩니다. HTTP/1.1에 정의되어 있는 헤더 필드에는 다음과 같이
47
종류가 있습니다.
일반적 헤더 필드(General Header Fields)
응답 메세지, 요청 메세지에 둘 다 사용되는 헤더입니다.
Cache-Control
: 캐시 동작 지정Connection
: Hop-by-hop 헤더, 커넥션 관리Date
: 메세지 생성 날짜Pragma
: 메세지 제어Trailer
: 메세지의 끝에 있는 헤더의 일람Transfer-Encoding
: 메세지 바디의 전송 코딩 형식 지정Upgrade
: 다른 프로토콜에 업그레이드Via
: 프록시 서버에 관한 정보Warning
: 에러 통지
요청 헤더 필드(Request Header Fields)
클라이언트에서 서버 측으로 송신된 요청 메세지에 사옹되는 헤더로 요청에 대한 부가적인 정보 혹은 클라이언트의 정보가 들어갑니다.
Accept
: 유저 에이전트가 처리 가능한 미디어 타입Accept-Charset
: 문자셋 우선 순위Accept-Encoding
: 콘텐츠 인코딩 우선 순위Accept-Language
: 언어(자연어) 우선 순위Authorization
: 웹 인증을 위한 정보Expect
: 서버에 대한 특정 동작의 기대From
: 유저의 메일 주소Host
: 요구된 리소스의 호스트If-Match
: 엔티티 태그의 비교If-Modified-Since
: 리소스의 갱신 시간 비교If-None-Match
: 엔티티 태그의 비교(If-Match의 반대)If-Range
: 리소스가 갱신되지 않은 경우에 엔티티의 바이트 범위의 요구를 송신If-Unmodified-Since
: 리소스의 갱신 시간 비교(If-Modified-Since의 반대)Max-Forwards
: 최대 전송 홉 수Proxy-Authorization
: 프록시 서버의 클라이언트 인증을 위한 정보Range
: 엔티티 바이트 범위 요구Referer
: 리퀘스트중의 URI를 취득하는 곳TE
: 전송 인코딩의 우선 순위User-Agent
: HTTP 클라이언트의 정보
응답 헤더 필드(Response Header Fields)
서버 측에서 클라이언트 측으로 송신한 응답 메세지에 사용되는 헤더로 서버의 정보, 혹은 클라이언트에게 추가적인 정보 요구 등을 부가합니다.
Accept-Ranges
: 바이트 단위의 요구를 수신할 수 있는지 없는지 여부Age
: 리소스의 지정 경과 시간Etag
: 리소스 특정하기 위한 정보Location
: 클라이언트를 지정한 URI에 리다이렉트Proxy-Authenticate
: 프록시 서버의 클라이언트 인증을 위한 정보Retry-After
: 리퀘스트 재시행의 타이밍 요구Server
: HTTP 서버 정보Vary
: 프록시 서버에 대한 캐시 관리 정보WWW-Authenticate
: 서버의 클라이언트 인증을 위한 정보
엔티티 헤더 필드(Entity Header Fields)
요청과 응답 메세지에 포함된 엔티티에 사용되는 헤더로 콘텐츠 갱신 시간 등의 엔티티에 관한 정보를 부가합니다.
Allow
: 리소스가 제공하는 HTTP 메소드Content-Encoding
: 엔티티 바디에 적용되는 콘텐츠 인코딩Content-Language
: 엔티티의 자연어Content-Length
: 엔티티 바디의 사이즈 (바이트)Content-Location
: 리소스에 대응하는 대체 URLContent-MD5
: 엔티티 바디의 메세지 다이제스트Content-Range
: 엔티티 바디의 범위 위치Content-Type
: 엔티티 바디의 미디어 타입Expires
: 엔티티 바디의 유효기간 날짜Last-Modified
: 리소스의 최종 갱신 날짜
쿠키를 위한 헤더 필드
서버와 클라이언트 간의 상태를 관리하는 쿠키는 HTTP/1.1 사양인 RFC2616에 포함된 것은 아니지만 웹 사이트에서 널리 사용되고 있습니다.
쿠키는 유저 식별과 상태 관리에 사용되고 있는 기능입니다. 웹 사이트가 유저의 상태를 관리하기 위해서 웹 브라우저 경유로 유저의 컴퓨터 상에 일시적으로 데이터를 기록해 두고, 다음에 그 유저가 웹 사이트에 액세스 해 왔을 때 지난번에 발행한 쿠키를 송신받을 수 있습니다.
쿠키를 위한 헤더 필드에는 Set-Cookie
, Cookie
가 있습니다.
Set-Cookie
는 서버가 클라이언트에 대해서 상태 관리를 시작할 때 다양한 정보를 전달합니다.
Set-Cookie
의 필드 속성들은 아래와 같습니다.
NAME
- 쿠키에 부여된 이름과 값, 필수입니다.
Expires
- 쿠키 유효 기간, 지정되지 않았으면 브라우저를 닫을 때 까지 유지됩니다. 한번 서버에 송출한 클라이언트의 쿠키는 서버에서 명시적으로 삭제하는 것이 불가능합니다. 유효 기간이 지났다면 쿠키를 덮어 쓰는 것으로 실질적인 클라이언트의 쿠키를 삭제하는 것이 가능합니다.
Path
- 쿠키를 송출하는 범위를 특정 디렉토리에 한정할 수 있습니다.
Domain
- 쿠키의 domain 속성에 의해서 지정된 도메인 명은 후방 일치가 됩니다. 예를 들면,
example.com
로 지정했을 때,example.com
이외에,www.example.com
,www2.example.com
등에서도 쿠키가 송출되기 때문에 여러 도메인에 대해서 쿠키를 송출하는 것 아니면 사용하지 않는 것이 좋습니다.
- 쿠키의 domain 속성에 의해서 지정된 도메인 명은 후방 일치가 됩니다. 예를 들면,
Secure
- 쿠키의 Secure 속성은 웹 페이지가 HTTPS에서 열렸을 때에만 쿠키 송출을 제한하기 위해서 지정합니다. 도메인이 같더라도 HTTPS가 아니면 쿠키를 송출하지 않습니다.
HttpOnly
- 쿠키의 HttpOnly 속성은 자바스크립트를 경유해서 쿠키를 취득하지 못하도록 하는 쿠키의 확장 기능입니다. 크로스 사이트 스크립팅(XSS)로부터 쿠키의 도청을 막는 것을 목적으로 합니다.
Max-Age
- 쿠키가 만료될 때 까지의 시간 (초 단위). 0 또는 음수가 지정되면 해당 쿠키는 즉시 만료되며, 오래된 브라우저(ie6, ie7 그리고 ie8)은 이 헤더를 지원하지 않습니다. 다른 브라우저들은 둘 다(Expires 와 Max-Age) 지정되었을 때 Max-Age 값을 더 우선시합니다.
그 이외의 헤더 필드
HTTP 헤더 필드는 독자적으로 확장할 수 있습니다. 그래서 웹 서버와 브라우저의 기능에 다양한 독자적인 헤더 필드가 존재합니다.
X-Frame-Option
X-XSS-Protection
DNT
P3P
HTTP/2.0
HTTP/1.x는 무슨 문제가 있었을까요?
HTTP/1.x
클라이언트는 동시성을 달성하고 대기 시간을 줄이기 위해 다중 연결을 사용해야 합니다.HTTP/1.x
는 요청 및 응답 헤더를 압축하지 않아서 불필요한 네트워크 트래픽을 사용합니다.HTTP/1.x
는 효과적인 리소스 우선 순위 지정을 허용하지 않아서 기본TCP
연결을 제대로 사용하지 못합니다.
HTTP/1.x
는 구현의 단순성을 위해 의도적으로 설계되었습니다. HTTP/0.9
는 WWW을 부트스트랩하기 위한 한 줄 짜리 프토토콜이었고, HTTP/1.0
은 약간의 확장과, HTTP/1.1
은 IETF
표준을 도입했습니다. 하지만 태생이 단순성을 위해 제작된 프로토콜이라서 애플리케이션의 성능을 희생시켰습니다.
HTTP/2.0
은 사용자가 웹을 이요할 때의 체감 속도의 개선을 목표로 하고 있습니다. HTTP 메서드, 상태 코드, URI 및 헤더 필드와 같은 모든 핵심 개념은 그대로 유지됩니다.
주요 변경 사항은 다음과 같습니다.
바이너리 프레이밍 레이어
바이너리 프레이밍 레이어를 통해서 HTTP 메세지를 캡슐화하고, 클라이언트 서버 간에 전송되는 방법을 지시하는 새로운 레이어를 만들어 데이터가 교환되는 방식을 바꿨습니다.
바이너리 프레이밍 레이어의 도입으로 새로운 용어들이 생겨났습니다.
스트림
: 하나 이상의 메시지를 전달할 수 있는 설정된 연결 내 바이트의 양방향 흐름입니다.메시지
: 논리적 요청 또는 응답 메시지에 매핑되는 전체 프레임 시퀀스입니다.프레임
: HTTP/2의 가장 작은 통신 단위로, 각각은 프레임 헤더를 포함하며 최소한 프레임이 속한 스트림을 식별합니다.
위의 개념들을 이용해서 하나의 TCP
연결 내에서 여러 개념들로 다중화시켜서 조금 더 효율적인 전송을 이뤄냅니다.
요청 및 응답 다중화
HTTP/1.x
에서는 클라이언트가 성능 향상을 위해 여러 개의 병렬 요청을 하려면, 여러 TCP 연결을 사용해서 기본 TCP 연결이 비효율적으로 사용된 것을HTTP/2.0
에서는 해결합니다.
HTTP/2의 새로운 이진 프레이밍 계층은 이러한 제한을 제거하고 클라이언트와 서버가 HTTP 메시지를 독립 프레임으로 분해하고 인터리브(HTTP 메세지를 서로 인접하지 않게 배열하는 방식하는 것을 의미합니다.)한 다음 다른 쪽 끝에서 재조립할 수 있도록 하여 전체 요청 및 응답 다중화를 가능하게 합니다.
HTTP/2의 새로운 이진 프레이밍 계층은 HTTP/1.x에서 발견되는 헤드 오브 라인 차단 문제를 해결하고 요청 및 응답의 병렬 처리 및 전달을 가능하게 하기 위해 다중 연결의 필요성을 제거합니다. 결과적으로 애플리케이션을 더 빠르고 간단하고 저렴하게 배포할 수 있습니다.
스트림 우선 순위 지정
HTTP/2.0에서는 HTTP 메세지를 여러 개의 개별 프레임으로 분할할 수 있고, 여러 스트림의 프레임을 다중화할 수 있게 되기 때문에 클라이언트와 서버 모두에게 전달되는 순서가 중요한 성능 고려 사항이 됩니다.
클라이언트는 응답 수신 방법을 나타내는 우선 순위 트리
를 구성하고, 서버에 전달합니다. 그러면 서버는 이 정보를 활용해서 우선 순위에 따라 클라이언트에게 최적으로 요청에 대한 응답을 전달할 수 있도록 우선 순위를 지정할 수 있게 됩니다.
오리진당 하나의 연결
HTTP/2.0에서는 더 이상 스트림을 병렬로 연결한다고 해서 TCP 연결도 병렬로 필요하지 않습니다. 결과적으로 HTTP/2.0에서의 오리진당 하나의
TCP
연결은 많은 이점을 제공합니다.
기본적으로 HTTP
는 짧고, 간단한 전송이 많은 반면에 TCP
는 수명이 긴 대량 데이터 전송에 최적화되어 있습니다. HTTP/2.0
에서는 하나의 TCP
연결을 재사용함으로써 조금 더 효율적으로 사용할 수 있고, 전체 프로토콜 오버헤드도 크게 줄일 수 있습니다. 결과적으로 아래와 같은 이점들을 얻을 수 있습니다.
- 클라이언트, 서버들의 메모리 및 처리 공간이 줄어듭니다.
- 전체 운영 비용을 줄이고, 네트워크 활용도와 용량을 향상시킵니다.
- 네트워크 대기 시간을 줄일 수 있고, 처리량을 개선할 수 있습니다.
흐름 제어
흐름 제어는 클라이언트가 원하지 않거나 처리할 수 없는 데이터로 서버를 압도하는 것을 방지하는 메커니즘입니다.
HTTP/2.0
에서 어떤 알고리즘 같은 것을 주는 것이 아닙니다. 흐름 제어에서 제공하는 스트림 흐름 제어 창
이라는 개념을 이용해서 리소스를 사용하고 할당을 규제하는 맞춤형 전략을 직접 구현할 수 있게 해줍니다.
서버 푸시
원래 클라이언트에서 요청이 시작되고, 서버는 그에 맞는 응답을 전해줄 뿐이었지만 HTTP/2.0에서는 단일 클라이언트 요청에 대해서 여러 개의 응답을 보낼 수 있는 서버의 기능입니다.
원래는 클라이언트가 HTML 필요해
, CSS 필요해
, JavaScript 필요해
와 같이 클라이언트가 서버로 요청을 보냅니다. 하지만 보통은 서버가 클라이언트에게 보내주는 리소스들은 정해져 있는 경우가 많습니다. 이 경우에 서버 푸시가 유용하게 사용됩니다. 추가 대기 시간을 없애고, 서버가 관련 리소스를 미리 푸시하는 것이죠.
헤더 압축
HTTP/1.x에서 헤더는 일반 텍스트로 전송되며 전송당 500-800 바이트의 오버헤를 추가하고, 쿠키를 사용하면 때때로 킬로바이트를 더 추가합니다. HTTP/2.0은 이 오버헤드를 줄이고 성능을 개선하기 위해서
HPACK
압축 형식을 사용해서 요청 및 응답 헤더를 압축시킵니다.
HPACK
의 간단 원리는 클라이언트와 서버 모두 주고 받은 헤더 필드를 유지하고 관리하고 업데이트해야 합니다. 이 공간을 활용해서 효율적으로 인코딩하기 위한 참조로 사용합니다.
HTTP/3.0
HTTP/2.0도 역시 멋져보이지만
TCP
를 사용한다는 것 때문에 한계가 있습니다. Handshake로 인한 지연시간은 해결할 수 없었습니다.
TCP
는 워낙 오래 전에 설계되기도 했고, 이런 저런 기능이 많습니다. 그래서 구글에서는 TCP
가 아닌, UDP
를 사용한 QUIC
프로토콜을 새로 내놓았습니다. HTTP/3.0
은 이 QUIC
기반으로 돌아갑니다.
QUIC
Quick UDP Internet Connection
의 약자로 UDP
를 사용해서 인터넷 연결을 하는 프로토콜입니다.
TCP와 UDP
- 연결 방식: TCP(연결형 서비스), UDP(비연결형 서비스)
- 패킷 교환: TCP(가상 회선 방식), UDP(데이터그램 방식)
- 전송 순서 보장: TCP(보장함), UDP(보장하지 않음)
- 신뢰성: TCP(높음), UDP(낮음)
- 전송 속도: TCP(느림), UDP(빠름)
HTTP/3.0
은 태생적으로 느릴 수 밖에 없는 TCP
를 사용하지 않고, 위의 제약들을 뛰어넘기 위해서 UDP
를 선택합니다. 기존 TCP
의 문제점은 아래와 같습니다.
- Three Way Handshake: 통신을 시작할 때와 종료할 때 서로 준비가 되어있는지 서로 확인하는 과정
- HOLB(Head of line Blocking): 어떤 요청에 병목이 생겨서 전체적인 레이턴시가 늘어난다는 개념
HTTP/3이 UDP
를 사용함으로써 기존보다 나아진 점은 아래와 같습니다.
- 연결 설정 시 레이턴시 감소: Three Way Handshake가 없음
- 패킷 손실 감지에 걸리는 시간 단축: 기존 통신과정에서 발생한 에러를 해결하는 방법을 개선함으로써 시간을 단축
- 멀티플렉싱 지원 (HOLB를 방지): 이것은
HTTP/2.0
에서 지원한 하나의TCP
연결에서 여러 스트림이라는 개념으로 데이터를 보내는 형식을 그대로 가져온 것입니다. - 클라이언트 IP가 바뀌어도 연결이 유지:
TCP
의 경우에 와이파이가 바뀌거나, 셀룰러 데이터를 사용하거나 이런 식으로 바뀌면IP 주소
가 바뀌는데TCP
는 이럴 때 다시 연결합니다. 그럼Three Way Handshake
를 다시 진행하는데QUIC
에서는 이것을 해결합니다.