HTTP는 HyperText Transfer Protocol의 약자로 TCP/IP 프로토콜을 기반으로 만들어진 클라이언트와 서버 사이에 이루어지는 요청/응답 프로토콜입니다.
단일 라인 요청으로 메서드는 GET이 유일합니다.
서버에 연결되면 프로토콜, 서버, 포트가 필요하지 않으므로 전체 URL이 포함되지 않았습니다.
오직 HTML만 전송할 수 있으므로 HTTP 헤더나 상태 혹은 오류 코드도 존재하지 않고, 오류 발생 시 HTML 파일 내부에 문제에 대한 설명을 작성하여 전달했습니다.
제한적인 HTTP/0.9를 해결하기 위해 등장했습니다.
각 요청에 버전을 포함하여 전달했고, 상태 코드 또한 응답으로 전송되었습니다.
HTTP 헤더가 요청과 응답에 모두 도입되어 메타데이터 전송이 가능했고, Content-Type 헤더로 HTML 외의 파일들을 전송할 수 있었습니다.
HTTP/1.1은 HTTP의 첫 번째 표준화 작업입니다.
persistent connection 모델인 헤더의 keep-alive 옵션을 통해 연결을 재사용할 수 있습니다. 기존의 HTTP는 매 요청마다 3 way handshake를 하며 새로운 TCP 연결을 맺어야했고 큰 오버헤드가 발생했으나 단일 연결로 처리할 수 있도록 하였습니다.
HTTP Pipelining을 통해 첫번째 요청에 대한 응답이 전송되기 전에 두번째 요청 전송을 가능하게 합니다.
Host 헤더를 통해 동일 IP에 다른 도메인을 호스팅할 수 있습니다.
하지만 HTTP Pipelining에도 HOL(Head of Line) Blocking 문제가 발생하였습니다.
HTTP에서 서버는 반드시 요청 순서에 따라 응답해야하는 규칙을 가지고 있고 a b c의 요청이 들어왔을 때 a의 요청이 지연된다면 b c의 요청을 바로 처리할 수 있어도 응답을 할 수 없는 문제가 발생하였습니다.
구글에서 만든 SPDY 프로토콜을 기반으로 한 HTTP/2는 HTTP/1.1의 성능 향상에 많은 개선을 가져왔습니다.
HTTP/1.1에서 발생하는 HOL Blocking을 병렬로 처리하는 방식으로 해결합니다.
우선 HTTP 2는 HTTP 1.1에서 텍스트로 전송되었던것과 달리 바이너리 프레임으로 인코딩되어 전송됩니다.
물론 실제 전송 단에서는 HTTP 1.1도 아스키 인코딩이 되지만, 프로토콜 레벨에서도 바이너리로 처리하기에 빠르고 안전한 처리를 지원합니다.
또한 요청과 응답을 메세지 단위로 나누고 각 메세지를 Header 프레임과 Data 프레임으로 나눕니다.
이러한 메세지를 여러 Stream 내에서 양방향으로 주고받아 병렬적으로(Multiplexing) 처리할 수 있도록 하였습니다.
리소스 간에 우선순위를 두어 클라이언트가 서버에 요청을 보낼 때 우선순위를 지정하고 보낼 수 있습니다.
서버는 우선순위가 높은 응답이 우선적으로 전달될 수 있도록 대역폭을 지정하는 방식으로 응답합니다.
또한 HTTP 헤더를 HPACK 방식으로 압축하여 데이터 전송 효율을 높입니다.
하지만, 여전히 TCP 자체에서 HOL Blocking이 발생하는 문제가 존재하고, Handshake의 무거운 연결에 대한 문제가 발생하고 있습니다.
Q. HTTP의 HOL Blocking 문제와 해결법을 알려주세요.
HOL(Head of line) Blocking 문제는 TCP 연결을 통해 전송되는 요청이 순차적으로 처리되어 앞의 요청이 지연되면 전체 요청이 지연되는 문제입니다.
HTTP/1.1에서는 한 번에 하나의 요청만을 처리하고 HTTP Pipelining을 지원하기는 하지만 서버는 요청과 응답의 일관성을 유지하기 위해 응답을 순서대로 보내야 해 앞선 요청이 지연되면 뒤따르는 요청도 지연되는 문제가 발생합니다.
이를 해결하기 위해 HTTP/1.1에서는 동시에 여러 TCP 연결을 열어 여러 요청을 보내는 도메인 샤딩 방법을 사용했습니다. 하지만 여러 연결에 대한 리소스가 소모되고, TCP 연결 수에 대한 제한이 있어 문제가 발생합니다.
HTTP 2에서는 멀티플렉싱을 통해 하나의 연결에서 여러 요청과 응답을 동시에 받을 수 있도록 하여 HTTP HOL 블로킹 문제를 해결했습니다.
하지만 HTTP 2에서도 TCP의 구조 상 패킷 전송 과정에서 HOL 문제가 발생하였고 HTTP3에서는 UDP로 전환하며 문제를 해결하였습니다.
Q. CORS(Cross Origin Resource Sharing)는 무엇인가요?
CORS는 다른 도메인에서 리소스를 요청할 때 요청을 허용할 지 여부를 지정하는 HTTP 헤더입니다.
서버에서 응답 헤더에 `Access-Control-Allow-Origin`을 담아 리소스 접근이 허용된 url을 보내는 방식으로 지원하게 됩니다.
웹의 보안 정책 중 하나인 동일 Same Origin Policy는 브라우저가 한 도메인에서 로드된 웹 페이지가 다른 도메인에서 리소스를 요청할 때에 이를 제한합니다. 사용자가 악성 사이트에서 잘못된 API를 호출하여 개인정보가 유출되는 상황 등을 막기 위함입니다.
하지만 백엔드 API를 호출하거나 CDN 리소스를 호출하는 등 여러 상황에서 다른 도메인의 API를 호출해야하고 CORS를 통해 이를 허용하게 합니다.
Q. HTTP의 stateless를 보완하기 위한 방법으로는 어떤게 있나요?
쿠키와 세션은 HTTP의 stateless를 보완하기 위한 방법입니다.
쿠키는 클라이언트에 저장되는 key-value 형태의 작은 데이터로 브라우저에 저장되어 보안이 낮지만 서버에 대한 요청이 없어 성능이 향상되고 간편하게 사용할 수 있다는 장점이 있습니다. 때문에 쿠키는 주로 장바구니나 사용자 설정 유지, 로그인 상태 유지 등에 사용됩니다.
반면 세션은 서버에서 사용자의 상태 정보를 저장하는 방법입니다. 클라이언트는 세션 ID만 보유하고 서버에 저장되어 보안이 높아 사용자 인증과 상태 관리 등의 중요한 정보를 처리하는데 사용됩니다.
Q. HTTP1.0의 성능적 단점을 설명하고 HTTP1.1에서 이를 보완하기 위해 새롭게 제시한 “연결 유지”와 “파이프라이닝”에 대해 설명하세요.
HTTP 1.0은 모든 요청에 대해서 새로운 TCP 연결을 맺고 3 way handshake를 하는 무거운 과정을 진행하여 성능이 좋지 않았습니다.
HTTP 1.1에서는 이를 보완하기 위해 persistent connection을 제안하였고 한 연결을 통해 여러 요청을 처리할 수 있도록 하여 매번 새로운 연결을 맺는 과정을 삭제하였습니다.
또한 파이프라이닝이라는 한 연결에서 아직 응답이 오지 않더라도 요청을 할 수 있도록 하여 전체적인 응답 시간을 단축하려는 노력을 하였습니다.
하지만 파이프라이닝은 HTTP1의 특성인 요청한 순서대로 응답이 와야된다는 문제로 HOLB 문제를 야기하였고 구현의 복잡성등의 이유로 대부분의 브라우저에서 지원하지 않습니다.
Q. HTTP 메서드들 중 리소스를 업데이트하는 PUT과 PATCH에 대해 설명하고 둘의 차이점에 대해 설명하세요.
PUT은 원하는 리소스가 없으면 생성하고 있다면 새로 보내는 데이터로 모두 수정하는 방식의 메서드입니다.
따라서 PUT은 멱등한 메서드입니다.
PATCH는 해당 리소스의 일부분을 수정하는 메서드로 만약 이름, 나이가 있는 데이터에 이름을 수정한다면 이름만 변경되는 메서드로 멱등하지 않습니다.
Q. HTTP2.0에서 헤더 압축(HPACK)을 사용하는 이유를 설명하고, HPACK의 방식을 들어 보완하세요.
HTTP2.0에서 헤더 압축(HPACK)을 사용하는 주된 이유는 성능 향상을 위해서입니다. HTTP 통신에서 헤더는 많은 정보를 포함하고 있고, 이 헤더 정보가 반복적으로 전송되는 경우가 많습니다. 이러한 반복적인 데이터 전송은 네트워크 자원의 낭비를 초래할 수 있습니다. 따라서, HPACK를 통해 헤더 데이터를 효율적으로 압축하고 전송함으로써 네트워크 자원을 절약하고, 전체적인 통신 성능을 향상시킬 수 있습니다.
HPACK의 방식은 다음과 같습니다. 클라이언트와 서버는 각각 헤더 필드 테이블을 유지합니다. 이 테이블은 고정 테이블과 동적 테이블로 구성되며, 고정 테이블에는 자주 사용되는 헤더 필드와 값이 미리 정의되어 있고, 동적 테이블에는 이전에 사용된 헤더 필드가 저장됩니다. 헤더 필드를 전송할 때, 헤더 필드 테이블에서 고정 테이블에 비하여 변경되는 부분의 헤더 필드를 찾아 인덱스 번호를 전송합니다. 만약 헤더 필드가 테이블에 없는 경우에는 헤더 필드를 문자열로 전송하고 동적 테이블에 추가합니다. 이렇게 함으로써 반복적으로 사용되는 헤더 필드의 전송을 최소화하고 데이터 전송량을 줄일 수 있습니다.