이제부터는 본격적으로 HTTP 에 대해 알아볼 것이다.
먼저, HTTP 에 대한 기본적인 내용을 살펴본 후 HTTP 메서드, 메서드의 활용, 상태코드, 헤더 순으로 살펴본다.
이번 포스팅에서는 HTTP 의 기본적인 개념들과 특성, 메시지의 간단한 구조에 대해 살펴볼 예정이다.
📌
HTTP
- HyperText Transfer Protocol 의 약어로, 처음에는
html
과 같은 하이퍼텍스트 문서를 전송하기 위한 프로토콜로 시작되었다.
➡️ 하이퍼텍스트에 대한 내용은 아래 포스팅을 참조할 수 있다.
HTTP 기초 - HyperText
먼저, HTTP
에 대한 기본적인 소개부터 시작하려고 한다.
위 인용문에서처럼, HTTP
는 html
과 같은 하이퍼텍스트 문서를 전송하기 위한 프로토콜로 시작되었다. 하지만 이제 우리가 알고 있는 거의 대부분의 format 들이 HTTP
에 담겨 전송될 수 있다.
html
은 물론이고 text
, image
, 음성
, 영상
, 파일
부터 시작해서 서버 간 통신할 때 사용되는 JSON
, XML
과 같은 API
까지, 거의 대부분의 data format 은 HTTP
로 전송이 가능하다.
즉, 모든 것은 HTTP
를 통해 전송될 수 있고 바야흐로 HTTP
시대가 도래하였다고 봐도 과언이 아닐 것이다.
✅ HTTP / 0.9 (1991)
✅ HTTP / 1.0 (1996)
✅ HTTP / 1.1 (1997)
✅ HTTP / 2 (2015)
✅ HTTP / 3 (진행중)
HTTP
는 1991년, 웹의 아버지이자 WWW
, URL
의 창시자인 Tim Berners-Lee
에 의해 고안되어 세상에 나왔다.
초창기에는 버전 정보가 없었지만, 이후 다른 버전과 구분하기 위해 Version 0.9
로 불리게 되었다고 한다. 또한, 이 때의 HTTP
에는 GET
메서드만 존재했으며, Header
가 없는 아주 단순한 구조였고 1996년이 되어서야 다양한 메서드와 Header
가 추가되었다.
우리가 가장 많이 사용하고 있으며, 우리에게 가장 중요한 버전인 HTTP / 1.1 은 1997년 개발되었다. 현재 2 버전과 3 버전이 존재하고 실제로 사용되고 있으나, 대부분의 스펙은 1.1 버전에 담겨있고 2 와 3 버전은 성능 개선에 초점이 맞추어져 있기 때문에 1.1 버전이 표준 프로토콜로 사용되고 있다.
⛔ 물론, 1997 년에 개발된 1.1 버전을 그대로 사용하고 있는 것은 아니다. HTTP / 1.1 내에서 내부적인 확장에 따라 꾸준히 업데이트되어 RFC2068
(1997) , RFC2616
(1999) 을 거쳐 RFC7230 ~ RFC7235
(2014) 까지 배포되었다.
추가적으로, HTTP / 1.1 과 HTTP / 2 는 TCP
위에서 동작하게 되고, HTTP / 3 에서는 TCP
대신 UDP
를 채택하여 TCP 3 Way Handshake
와 TCP Header
에 낭비되는 시간과 메모리를 줄이고 성능을 향상시켰다. 최근에는 HTTP / 2 와 HTTP / 3 버전도 증가하고 있는 추세이다.
실제로, 웹브라우저에서도 F12
의 Network
탭을 클릭하여 사용하는 프로토콜 정보를 확인해볼 수 있는데, http/1.1
을 사용하기도 하고 h2
를 사용하기도 한다. h2
는 http/2
를 의미한다.
구글에 'hello' 를 검색했을 때는 h3
, 즉 http/3
를 사용하는 모습도 확인할 수 있다.
이렇게 HTTP
는 다양한 버전들이 함께 사용되고 있으며, 우리는 학습 시에 표준 프로토콜인 HTTP/1.1
을 기준으로 살펴보게 될 것이다.
이제 HTTP
가 가지는 여러가지 특징에 대해서 알아본다.
📌
HTTP
의 특징은 크게 다음과 같다.
Client - Server
구조Stateless
andConnectionless
HTTP Message
Simplicity
andExtensibilty
HTTP
는 기본적으로 클라이언트-서버 구조로 이루어져 있다.
클라이언트는 HTTP 메시지
를 매개로 서버에 Request
를 보내고, 서버에서 다시 Response
가 도착할 때까지 응답을 대기한다. 이후, 서버로부터 응답이 도착하면 이를 해석하여 그에 따른 동작을 수행하게 된다. 이는 앞선 포스팅에서 살펴보았던 웹브라우저 요청 흐름에서도 잘 나타난다.
✅ 즉, HTTP
는 클라이언트와 서버의 요청/응답 흐름에 의해 상호작용하며 작동하게 되는 것이다.
이렇게 클라이언트와 서버로 분리된 구조는 사실 HTTP
에서 굉장히 핵심적인 특징인데, 그 이유는 유지보수성과 확장성에 있다고 볼 수 있다.
클라이언트와 서버를 개념적으로 분리시킨 후 서버에 비즈니스 로직이나 데이터들을 모두 밀어넣어 설계하게 되면, 클라이언트에서는 UI 로직이나 UX 와 같은 사용성에 집중할 수 있게 되고 결과적으로 양단(클라이언트, 서버)이 각각 독립적으로 진화할 수 있게 된다. 클라이언트 단에서 중요하고 복잡한 비즈니스 로직이나 데이터와 관련된 작업을 신경써야 할 일이 없어지게 되기 때문이다.
반대로 서버 단에서도 트래픽으로 인한 장애 발생 시, 클라이언트에 손을 댈 필요가 없어진다. 따라서, 대용량 트래픽을 받아낼 수 있는 아키텍처를 고민하고, 백엔드 관련 기술의 고도화에 대해 집중적으로 고민할 수 있도록 돕는다.
이는 마치, 모듈 설계 시 각 모듈 간 낮은 결합도를 가지도록 구현하여 Loosely Coupled 한 모듈 간 의존성으로부터 다양한 이점을 얻을 수 있는 원리와 유사해보인다.
결론적으로, 유지보수는 물론 확장성에 있어서 클라이언트-서버 구조는 이점을 가져다 준다고 볼 수 있으며, 가히 HTTP
의 핵심적인 특징이라고 볼 수 있다.
HTTP
의 두 번째 특징은 Stateless 를 지향한다는 점인데, 이는 서버가 클라이언트의 상태를 보존하지 않는다는 뜻이다. 반대로, 서버가 클라이언트의 상태를 보존한다면 Stateful 하다고 표현한다.
이 두 개념에 대해서는 아래에서 비교하며 살펴보도록 한다.
먼저, Stateful 에 대해서 간단한 예시를 살펴보자.
전혀 이상하지 않은 일상적인 대화이다. 고객은 매 대화마다 자신의 요구사항에 대해 간결하고 정확하게 전달하고 있으며, 점원은 고객의 모든 요구사항에 대해 정확하게 기억하면서 그에 맞춰 올바른 동작을 수행하고 있다.
이제 고객은 요청을 보내는 클라이언트이고, 점원은 요청을 받아 응답을 보내는 서버라고 생각해보자.
서버는 클라이언트와의 매 대화마다 이전의 내용을 누적해서 기억하고 그에 맞는 응답을 생성하고 있다. 결과적으로 클라이언트는 이전 대화내용을 다시 반복하여 전달할 필요없이 그때마다 필요한 요청만을 전달할 수 있다. 여기서 서버가 기억하는 내용은 노트북
2개
신용카드
정도가 될 것이고, 이 상태를 누적해서 유지시키기 때문에 클라이언트와의 자연스러운 대화가 가능해진다.
즉, Stateful 은 서버가 매 대화마다 이전 대화의 상태를 유지하고 기억함으로서 클라이언트가 이전 대화의 정보를 전달하지 않아도 올바른 응답을 생성할 수 있는 것이다.
여기까지 보면, Stateful 은 클라이언트의 부담을 줄여주어 그 자체로 장점이 가득한 설계로 느껴질지도 모르지만 다음과 같은 한계가 존재한다.
위는 Stateful 에서 점원이 매 대화마다 바뀔 경우의 예시이다.
고객은 요구사항에 대해 각각 다른 점원에게 전달하고 있고, 결국 어떤 점원도 고객의 최종 요구사항을 이해하지 못한다. 고객의 요구사항 각각( 노트북
2개
신용카드
)은 서로 다른 점원이 기억하고 있기 때문이다.
즉, Stateful 한 설계의 가장 큰 단점은 하나의 클라이언트와 통신하는 서버가 여러대 존재할 경우, 서로 다른 서버에 저장된 클라이언트의 상태 정보가 무시될 우려가 있고 이렇게 되면 클라이언트는 요구사항에 대한 정확한 응답을 받을 수 없는 문제가 발생한다는 것이다.
그렇다면, 클라이언트의 상태를 유지하지 않는 Stateless 에서는 과연 어떨까?
아래는 Stateless 에서의 대화 예시이다.
Stateless 에서는 서버가 클라이언트의 상태를 유지하지 않는다. 따라서, 서버가 이전 대화 내용에 대해 기억하고 있지 않기 때문에 클라이언트는 자신이 필요한 요구사항에 대해 그때그때 모두 전달해주어야 한다. 살짝 어색한 대화처럼 느껴질지 모르지만, 아래의 예시를 보면 Stateless 의 장점이 와닿는다.
Stateless 에서는 하나의 클라이언트와 통신하는 서버가 여러대 존재한다고 하더라도 그때마다 필요한 모든 정보를 전달하기 때문에 문제가 발생하지 않는다. 위 예시에서 중간에 점원이 바뀌고 있음에도 불구하고 고객의 결제가 성공적으로 완료되었음을 알 수 있다!
이러한 HTTP
의 Stateless 한 특징은 상당한 이점을 가지고 있는데, 바로 서버의 무한한 증설이 가능하게 해준다는 것이다.
바로 위의 예시에서도 알 수 있듯이, Stateless 에서는 중간에 점원이 바뀌더라도 고객은 정상적으로 요청에 대한 응답을 받아낼 수 있었다. 이는 고객이 갑작스럽게 증가한다고 하더라도 점원을 대거 투입할 수 있다는 의미이기도 하다. 어떤 점원을 만나더라도, 중간에 다른 점원을 만나더라도 고객은 누구에게나 자신의 요구사항을 전달할 수 있기 때문이다.
즉, 갑자기 트래픽이 증가하여 클라이언트의 요청이 많아지게 되더라도 서버를 대거 투입하여 이에 대한 대응을 해낼 수 있다. Stateless 에서는 상태를 유지하지 않으므로 응답 서버를 부담없이 바꿀 수 있어 무한한 서버 증설이 가능하기 때문이다. 이렇게 서버를 수평적으로 증설 및 확장하는 것을 Scale Out이라고 한다.
➡️ Scale Out 과 Scale Up 의 자세한 내용에 대해서는 아래 글을 참고바란다.
Scale-up과 Scale-out에 대해 알아보자!
반면, Stateful 에서는 중간에 점원이 바뀌어선 안된다. 하나의 클라이언트는 무조건적으로 하나의 서버와 통신하여야 한다. 즉, 클라이언트 요청이 갑작스럽게 증가하였을 때 서버를 무한히 증설한다고 하더라도 서버의 자원을 효율적으로 사용할 수 없게 되고 그에 따라 트래픽 증가에 대한 유연한 대응이 어려워지게 되는 것이다.
물론, Stateful 에서 각 서버(점원)가 서로 통신하며 클라이언트의 상태 정보에 대해 주고받는 과정이 추가된다면 문제가 해결 가능하겠지만, 기본적으로 Stateless 가 서버의 수평적 증설 및 확장에 있어 더 유리한 설계구조를 갖는다는 것은 명확해보인다.
Stateless 가 갖는 이점은 이뿐만이 아니다.
아래의 그림을 살펴보자.
Stateful 에서 클라이언트와 서버 간 통신 중 서버에 장애가 발생하게 되면, 해당 서버는 지금까지 유지하고 있었던 클라이언트의 상태 정보들을 모두 잃게 되고, 클라이언트는 다시 다른 서버와 같은 대화를 반복하여야 한다.
반면, Stateless 에서는 서버가 클라이언트의 상태 정보를 유지하지 않고, 클라이언트는 요청시에 필요한 모든 정보를 한꺼번에 전달하므로 그저 다른 서버를 호출하여 손쉽게 요청을 전달하고 응답을 받을 수 있다.
지금까지 Stateless 가 서버의 수평적 확장인 Scale Out 에서도 유리하고, 서버 장애 발생 시에도 이점을 가진다는 내용에 대해 살펴보았다.
그렇다면 Stateless 에게 단점은 없을까?
이는 단점이라기보다 Stateless 의 한계에 가까운 내용인데, 사실 모든 서비스를 Stateless 로 설계하기란 어려운 일이다.
예를 들어, 우리가 사용하는 서비스 중에는 로그인이 필요없는 단순한 화면이 있을 것이고, 사용자의 로그인 정보가 필요한 화면도 존재할 것이다.
물론, 로그인이 필요없는 단순한 페이지의 경우에는 Stateless 로 설계하기 어렵지 않다. 하지만, 사용자의 로그인 정보가 필요한 페이지의 경우, 사용자가 로그인하였다는 상태 정보를 서버에서 지속적으로 유지해주어야 하기 때문에 기본적으로 Stateless 를 지향하는 HTTP
입장에서는 이를 설계하기 굉장히 까다로울 것이다.
따라서, 이런 경우에는 일반적으로 브라우저의 쿠키와 서버의 세션을 활용해서 상태를 유지시켜주는 방법을 사용한다. 하지만, 세션쿠키 또한 상태를 유지시켜주는 역할을 수행하기 때문에 부분적으로 Stateful 하다고 볼 수 있다.
두 번째로, Stateless 의 단점은 클라이언트가 전송하는 데이터가 많아진다는 것이다.
앞선 대화 내용 예시에서처럼, 클라이언트는 자신의 요청에 필요한 모든 정보를 한 번에 전송해야 하기 때문에 결과적으로 요청 시 전달하는 데이터의 크기가 커질 수 밖에 없다. 이는 클라이언트 단에서 전송해야하는 데이터의 크기가 커짐에 따라 그 부하가 발생한다는 것이다.
하지만, 이러한 한계나 단점에도 불구하고 Stateless 하게 설계하는 것이 여러모로 다양한 이점을 제공해주기 때문에 실제로도 Stateless 한 설계가 권장되고 있다.
즉, 웹 애플리케이션을 설계할 때는 최대한 Stateless 하게 설계하고, 불가피하게 상태를 유지시켜주어야 하는 경우에만 최소한으로 Stateful 한 설계를 진행하는 것이 바람직하다.
HTTP
는 Connectionless, 즉 비연결성의 특징을 갖는다.
비연결성은 클라이언트와 서버 간 연결을 유지하지 않는다는 의미인데, 이 또한 아래에서 연결을 유지하는 모델과 비교하며 그 개념에 대해 알아보려 한다.
위 그림은 클라이언트와 서버 간 연결을 유지하는 예로서, TCP/IP
는 연결을 유지하는 대표적인 모델이다.
그림을 잠시 살펴보면, 클라이언트는 총 3 대가 존재하고 서버는 1 대가 존재한다. 이 때 서로 간을 잇는 직선은 연결이 되어있음을 의미하는데, 3 대의 모든 클라이언트가 서버와 연결되어 있다. 즉, 클라이언트 1 이 특정 서버와 연결을 맺고, 이후 클라이언트 2 가 같은 서버와 연결을 맺고, 마지막으로 클라이언트 3 이 또 같은 서버와 연결을 맺는 상황에서 서버는 모든 클라이언트와 연결을 유지하느라 자원을 계속 소모하고 있는 것이다.
실제로 서버는 현재 클라이언트 3 과 Request
Response
를 주고 받고 있고, 클라이언트 1 과 2 는 사용하지 않으면서도 연결을 계속해서 유지하고 있는 모습을 직관적으로 확인할 수 있다.
이는 TCP/IP
와 같은 연결을 유지하는 모델의 가장 큰 단점인데, 현재 사용하지 않는 클라이언트와의 연결을 유지하는데 서버의 가용 자원을 지속적으로 소모하게 된다는 것이다.
그렇다면 연결을 유지하지 않는 Connectionless 는 어떨까?
위 그림은 연결을 유지하지 않는 모델의 예시이다. 클라이언트와 서버가 일차적으로 TCP/IP
연결을 맺고 Request
와 Response
를 주고받은 뒤에 자동으로 연결이 종료되는 모습을 확인할 수 있다.
클라이언트와 서버가 서로 볼일이 끝나면, TCP/IP
위에서 동작하는 HTTP
가 기본적으로 Connectionless 를 지향하기 때문에 TCP/IP
연결을 자동으로 종료하게 되는 것이다.
물론, 이후 다른 클라이언트와의 연결에서도 동일하게 동작한다. 클라이언트 2 와 서버가 새롭게 연결을 맺는 상황에서, 클라이언트 1 과의 연결을 유지하지 않고 있다.
이렇게 Connectionless 를 지향하는 모델에서 서버는 최소한의 자원만을 유지할 수 있다. 클라이언트와 Request
Response
를 주고받을 때만 연결을 유지하고 이후에는 끊어버리기 때문에 서버가 유지하는 자원을 최소한으로 줄일 수 있는 것이다. 물론, 다른 클라이언트와의 연결이 필요하게 되면, 그 때 다시 연결하면 된다.
사실 이러한 Request
Response
를 주고받는 과정은 일반적으로 초 단위 이하의 빠른 속도로 이루어지기 때문에 조금의 트래픽이 발생한다고 하더라도 실제로 서버에서 동시에 처리해야 하는 요청은 매우 작은 개수일 것이다. 초 단위 이하의 시간에 동시에 같은 버튼을 연속해서 누르는 일은 많지 않기 때문이다. 따라서, Connectionless 한 특성때문에 동시에 들어오는 클라이언트의 Request
에 응답하지 못하는 문제는 잘 발생하지 않는다고 봐도 무방하다.
⛔ 물론, 이벤트와 같은 대용량 트래픽이 정확한 시간에 맞추어 발생하는 경우에는 문제가 발생할 수 있으며, 이 때는 이벤트 소개 페이지와 같은 Stateless 한 정적 페이지를 첫 화면에 뿌려 버튼 클릭에 클라이언트별 시간차를 의도적으로 발생시켜 해결하기도 한다.
정리하자면, HTTP
는 기본적으로 연결을 유지하지 않는 모델이다. 따라서, 클라이언트와 Request
Response
를 주고받을 때만 연결을 유지하여 서버가 최소한의 자원만을 유지할 수 있도록 도와 효율적인 자원관리를 가능케 한다.
물론 Connectionless 에도 단점이 존재하는데, 매번 TCP/IP
연결을 새로 맺어야 한다는 점이다.
클라이언트와의 연결을 유지하지 않고 Request
Response
이후 연결을 끊어버리기 때문에 클라이언트에서 추가적인 Request
가 들어오면, 그에 따라 TCP 3 Way Handshake
를 거쳐 새롭게 TCP/IP
연결을 맺어주어야 한다.
즉, 우리가 웹서핑을 할 때 새로운 버튼을 클릭할 때마다 TCP 3 Way Handshake
로 TCP/IP
연결을 새로 맺어야 하니 그만큼 시간이 추가되는 문제점이 발생하는 것이다. 특히, 웹 브라우저로 사이트를 요청하게 되면 html
뿐 아니라 JS
, CSS
, Image
등 수많은 자원들이 함께 다운로드되는데, 이 모든 자원들에 대해 하나씩 새로운 TCP/IP
연결을 시도하여야 한다는 건 굉장히 비효율적이다.
위 그림에서는 각 자원들에 대해 새롭게 연결을 맺고 종료하는 과정이 반복되고 있는데, 굉장히 비효율적으로 보인다.
⛔ 참고로 그림에서의 각 시간은 이해를 돕기 위한 예시일 뿐이다.
따라서, HTTP
에서는 Persistent Connections 라 불리는 지속 연결
을 통해 이러한 문제점을 해결한다.
위는 HTTP
의 Persistent Connections 의 예시이다. 처음에 TCP/IP
연결을 맺고 Request
Response
를 주고받은 뒤에도 연결을 끊지 않고 유지하는 모습을 확인할 수 있다. 일시적인 연결 유지를 통해, 반복적인 TCP/IP
연결 과정을 생략하고 웹사이트 요청에 필요한 대부분의 데이터를 모두 주고받은 후 연결을 종료하는 것이다.
⛔ 이 때, 일시적으로 연결을 유지하는 시간은 내부 매커니즘에 따르는데, 보통 Request
에 필요한 모든 Response
를 충분히 확보할 수 있을 만한 시간으로 설정된다.
결론적으로 HTTP
는 Persistent Connections 를 통해 반복적인 TCP/IP
연결 과정을 생략하여 최종적으로 Connectionless 가 가진 한계를 극복한다. 또한, HTTP/2
와 HTTP/3
버전에서는 이러한 기능이 더욱 최적화되었다고 한다. 특히, HTTP/3
에서는 UDP
를 채택하면서 TCP 3 Way Handshake
를 이용하지 않아 초기에 연결 속도 자체도 획기적으로 줄일 수 있었다고 한다.
마지막으로, HTTP 메시지의 구조를 살펴본다.
이번 포스팅에서는 대략적인 구조에 대해서만 언급되며, 헤더와 바디 내 구성요소들의 자세한 내용은 앞으로 포스팅될 시리즈 내에서 차차 소개할 예정이다.
먼저, HTTP 메시지의 전체적인 구조를 그림으로 확인해보자.
HTTP 메시지는 Start-line
Header
Empty-line
Body
의 네 부분으로 구성되어 있다. 이 중, Empty-line
은 공백 라인으로 Enter
에 해당하며, 필수적으로 포함되어야 하는 구성요소이다.
실제로도 HTTP/1.1 RFC7230
의 spec 을 보면,
필수 요소인 Start-line
과 Empty-line
, 여러 개의 Header
필드들과 생략가능한 Body
가 포함되어 있는 모습을 확인할 수 있다.
사실 HTTP 메시지의 전체적인 구조는 위와 동일하지만, Request
와 Response
별로 내부 구성요소가 약간씩 다르다. 이에 대해서는 각 파트에 대해 살펴보면서 비교해보도록 하자.
위에서부터 차례대로 Request
메시지, Response
메시지의 예시이다. 요청 메시지에는 Body
가 생략되어 있으므로 전체적인 구조는 모두 동일한 것을 알 수 있다. 하지만, 각 구조 내에서 내부적인 요소들에 차이가 있다.
먼저, 가장 위에 위치하는 요청 메시지의 Start-line
이다.
요청 메시지의 Start-line
은 Request-line
으로 불린다.
📌
Request-line
=HTTP Method
+SP
+Request-Target
+SP
+HTTP-Version
+CRLF
이 때 Request-line
은 HTTP Method
와 요청 대상인 Request-Target
, 그리고 HTTP-Version
으로 구성되어 있다.
중간의 SP
는 공백을 의미하며 마지막 CRLF
는 Enter
를 의미한다.
HTTP Method
는 클라이언트가 서버에게 요청하는 명령어이자 메서드라고 이해하면 쉽다. 메서드에 대해서는 이후 포스팅에서 따로 다룰 예정이다.
Request-Target
은 요청 대상이다. 주로 /
로 시작하는 절대경로와 쿼리가 들어가게 된다.
HTTP-Version
은 말그대로 사용하는 HTTP
의 버전 정보를 의미한다.
⛔ 위 예시에서는 'GET' 이 HTTP Method
이고, '/search?q=hello&hl=ko' 가 요청 대상, 즉 Request-Target
이 될 것이며 'HTTP/1.1' 이 HTTP-Version
에 해당할 것이다. 그리고 각 부분은 공백에 의해 구분되어 있다.
다음은 응답 메시지의 Start-line
이다.
응답 메시지의 Start-line
은 Status-line
으로 불린다.
📌
Status-line
=HTTP-Version
+SP
+Status-Code
+SP
+Reason-Phrase
+CRLF
이 때 Status-line
은 HTTP-Version
이 제일 앞에 오고, Status-Code
, 그리고 Reason-Phrase
로 구성되어 있다.
물론, SP
와 CRLF
도 동일하게 포함되어 있다.
Status-Code
는 상태코드
라고도 불리는데, 클라이언트의 요청이 성공했는지, 실패했는지를 의미한다.
Reason-Phrase
는 상태코드를 직관적으로 이해하기 위해 텍스트로 표현한 짧은 문구이다.
⛔ 위 예시에서는 'HTTP/1.1' 이 HTTP-Version
, '200' 이 Status-Code
, 'OK' 가 Reason-Phrase
에 해당할 것이다. 즉, 클라이언트의 요청이 성공적으로 완료되었음을 의미한다고 볼 수 있다.
Header
에는 HTTP
전송에 필요한 모든 부가 정보가 담긴다.
Body
의 내용과 관련한 정보부터 시작해서 Body
의 크기, 압축, 인증, 요청 클라이언트의 브라우저 정보, 서버 애플리케이션 정보, 캐시 관리 정보 등 그 요소는 매우 다양하다. 심지어 필요시에는 임의의 요소를 추가할 수도 있다.
우선 기본적인 Header
의 구조는 다음과 같다.
📌
Header
=Field-Name
+:
+OWS
+Field-Value
+OWS
헤더에 넣고자하는 Field-Name
과 :
을 작성하고, 그 뒤에 Field-Value
를 작성하는 식인데, 일반적인 key-value 타입을 작성하는 방식과 동일하다고 보면 된다.
하지만, OWS
와 같은 '띄어쓰기 허용' 에 대한 명시가 없는 공간에는 SP
를 사용할 수 없다. 즉, OWS
에는 SP
를 사용해도 되고, 사용하지 않아도 된다.
위에서부터 요청 메시지의 Header
, 응답 메시지의 Header
예시이다.
앞서 살펴본 구조에 따라 작성된 것을 확인할 수 있다.
특히, OWS
가 없는 Field-Name
과 :
사이에는 SP
가 사용되지 않았다.
또한, Header
에는 요청메시지와 응답메시지 별로 각각 전송에 필요한 정보들이 포함되어 있다. 그 중에는 서로 공통적으로 포함되어야 하는 Field
도 있을 것이고, 그렇지 않은 Field
도 있을 것이다. 이번 포스팅에서는 요청/응답 메시지의 Header
에 대해 비교하지 않았다.
여기서는, 기본적인 Header
의 구조와 전송에 필요한 다양한 메타데이터 정보가 담긴다는 점 정도만 알고 넘어가도 좋을 듯 하다.
⛔ Header
에 포함되는 다양한 Field
에 대해서는 이후 따로 정리하여 포스팅할 예정이다.
Body
에는 실제 전송할 데이터가 담기게 된다.
이는 html
이 될 수도 있고, Image
Video
JSON
XML
등 byte 로 표현될 수 있는 모든 데이터가 될 수도 있다.
추가적으로 데이터를 압축하여 담아 보낼 수도 있다.
예시에서는 요청 메시지의 Body
는 생략되어 있고, 응답 메시지의 Body
에 html
데이터가 담겨 있는 모습을 확인할 수 있다.
이는 클라이언트가 GET 메서드를 활용해서 웹사이트를 요청하였기 때문에 그에 대한 응답을 반환하는 과정이라고 생각할 수 있다.
지금까지 HTTP
의 개념들과 역사, 특성들에 대해 살펴보았다.
그 중 HTTP
의 특성에는 Client-Server
구조, Stateless
, Connectionless
가 있었고, 마지막에는 HTTP Message
의 구조까지도 알아보았다.
간단히 요약하면,
HTTP
는 총 4 가지의 파트로 나뉘어 굉장히 단순한 구조를 가지고 있었고,
Client
와 Server
가 분리되어 각각 독립적으로 확장 및 유지보수하기에 유리했다.
또한, Stateless
하고 Connectionless
한 설계로 인해 Scale-Out 이나 장애 대응, 서버 자원의 효율적 관리 측면에서도 이점을 가질 수 있었다.
즉, HTTP
가 성공한 이유는 복잡하고 잘 만들어졌기 때문이 아니라, 단순하면서 확장이 가능했기 때문인 것이다.
일반적으로 크게 성공하는 표준 기술은 단순하지만 확장 가능한 기술이라고 한다. 바로 HTTP
도 이러한 단순함과 확장성 덕분에 전세계 모든 웹의 기반으로 동작하는 표준 기술로 자리잡은 것이 아닐까 생각한다.