[ CS > Network ]
[HTTP] HTTP란
HTTP(Hypertext Transfer Protocol)
최근 면접을 보면서 기초들을 많이 까먹었고 제대로 정리되어 있지 않다고 느꼈습니다. 그래서 기초부터 다시 처음 배우는 마음가짐으로 글을 작성합니다... ㅜㅜ
HTTP는 리소스들을 가져올 수 있도록 해주는 프로토콜이다. 특히 웹에서 이루어지는 데이터 교환의 기초이며, 주로 Server-Client간의 통신 프로토콜이다. 보통 웹 브라우저(크롬, 사파리 등)가 Client이고 Tomcat, Nginx 같은 것들이 Server 역할을 한다.
1. 리소스
웹 서버는 리소스를 관리하고 제공한다. 웹 서버의 정적 파일을 전달해줄 수도 있지만, 누가 언제 요청했는지에 따라 동적으로 데이터를 전달해줄 수 있다. 예를들면 로그인시에 유저별로 받아오는 닉네임 정보는 다를 것이다. 그리고 이 웹 클라이언트는 용도에 맞는 웹서버를 통해 이러한 데이터들을 전달받는다.
1.1 MIME(미디어 타입, Content-type)
MIME(Multipurpose Internet Mail Extensions)는 각기 다른 메일 시스템 사이에서 메시지가 오갈 때 겪는 문제점을 해결하기 위해 설계되었습니다. 더 자세하게는 각 메일 시스템이 자기 방식대로 첨부파일을 인코딩 처리하기 때문에, 어떤 파일인지와 인코딩 방식을 지정하여 호환되도록 만들기 위함이였습니다. HTTP통신에서도 다양한 유형의 파일을 전달하기 때문에 전달할 데이터에 대해서 MIME 타입을 통해 확인가능 하도록 만들어야 했습니다.
그래서 HTTP에서는 Content-type(데이터 형식), Content-length(데이터 크기), Content-Encoding(압축 방식)이라는 헤더를 통해서 데이터의 형식과 압축 방식을 보내주고, 웹 클라이언트에서는 해당 정보를 활용하여 데이터를 알맞게 처리합니다.
HTTP에서 이미지를 받으면 MIME는 다음과 형식으로 받아올 것입니다.HTTP/1.1 200 OKContent-Type: image/jpegContent-Length: 245760Content-Encoding: gzipContent-Type: {주타입}/{부타입}; charset={인코딩 방식,utf-8 등}Content-Length: 파일 크기Content-Enccoding: {압축방식, gzip 등등
1.2 URI (uniform resource identifier, 통합 자원 식별자)
웹 서버 리소스는 각자 이름을 갖고 있고, 클라이언트는 해당 리소스를 지목할 수 있어야 한다. 그리고 이러한 서버 리소스의 이름을 URI라고 부른다. 이 URI는 정보 리소스를 고유하게 식별하고 위치를 지정할 수 있도록 도와준다.
예를들면 이 블로그 배경화면 동영상의 URI는 https://api.yooncarrot.com/static/home/background2.mp4이다.(S3서버 주소와 S3에서 해당 파일의 리소스 위치를 알면, S3서버 주소를 통해 접근할 수도 있다.)
URI는 URL과 URN 2가지 종류가 있다.
URL(uniform resource locator)
특정 서버의 한 리소스에 대한 구체적인 위치를 의미한다. 그리고 URL은 3 부분으로 이루어진다.
스킴(scheme): https://(보통 사용되는 프로토콜)
서버의 인터넷 주소(도메인) : api.yooncarrot.com
서버에서 리소스 위치: /static/home/background2.mp4
URN(uniform resource name)
리소스 위치에 영향없이 유일한 이름 역할을 한다. 리소스 위치를 옮기더라도 이 URN은 문제없이 작동해야하며, 프로토콜 상관없이 접근할 수 있다. (urn:네임스페이스:네임스페이스에서이름 으로 된다. urn:isbn:9780134092669) 보통 책, 논문 정보를 이런식으로 저장한다. 현재는 사실상 거의 쓰이지 않는다.
2. 트랜잭션
HTTP 트랜잭션은 요청(client -> server)과 응답(server -> client)로 구성된다. 그리고 이 상호작용은 정형화된 HTTP 메시지로 이루어진다.
요청
GET /static/home/background2.mp4 HTTP/1.1
Host: api.yooncarrot.com응답
HTTP/1.1 200 OK
Content-type: video/mp4
Content-Length: 981314
요청 에는 HTTP 메서드 정보, 보낼 서버 주소, 경로가 포함되며 응답에는 프로토콜 버전, 응답 상태, MIME 정보 등이 포함된다. 그리고 웹페이지를 띄우기 위해서 보통 여러번의 HTTP 트랜잭션을 거친다.(HTML문서를 가져오고, JS 파일 가져오고, 이미지 가져오고...)
2.1 HTTP 메서드
클라이언트는 요청을 할 때 HTTP 메서드로 서버가 어떤 동작을 취해야 하는지 알려준다.
메서드 | 설명 |
GET | 지정한 리소스를 클라이언트에게 보내라 |
PUT | 클라이언트에서 서버로 보낸 데이터를 지정한 이름의 리소스로 지정하라 |
DELETE | 지정한 리소스를 서버에서 삭제하라 |
POST | 클라이언트 데이터를 서버 게이트웨이 애플리케이션에 전송하라 |
HEAD | 지정한 리소스의 HTTP 헤드 부분만 클라이언트에게 보내라 |
OPTIONS | 서버에서 어떤 메서드가 가능한지 클라이언트에게 알려주라 |
2.2 상태 코드
모든 HTTP 응답에는 상태 코드와 사유 구절(OK와 같은 문구)을 함께 보낸다. 사유 구절은 단순 참고용으로 상태는 HTTP Status Code를 통해 처리된다.
상태코드 | 설명 |
200 | 정상 |
302 | 리소스가 일시적으로 이동되었으니 redirect 해라 |
404 | 없는 리소스 |
3. 메시지
HTTP 메시지는 binary형식이 아닌 일반 텍스트이기 때문에 읽고 쓰기가 쉽다. 그리고 이 HTTP 요청과 응답은 시작줄, 헤더, 바디와 구분을 위한 빈줄, 본문으로 이루어져 있다.

시작줄
요청이라면 무엇을 해야하는지 서버에게 전달하고, 응답이라면 무슨일이 있어났는지 클라이언트에게 전달한다.
헤더
헤더는 key value를 쌍점(:)으로 구분되어 전달되게 된다. 값을 추가한다면 1줄을 추가하면 된다.
본문
본문은 헤더의 빈줄 다음에 나온다. HTTP 메시지는 본문에 바이너리 데이터를 포함할 수 있다.
4. TCP 커넥션
HTTP 통신을 하기 위해서는 TCP 커넥션이 필요하다. 그리고 HTTP는 네트워크 개념에서 TCP 위의 계층이다

위와 같이 다양한 네트워크 모델이 있는데, 이중에서 최근 업데이트된 TCP/IP 5계층을 기준으로 HTTP가 전송되는 과정을 표로 정리하면 다음과 같다.

그리고 그 전송 과정을 그림으로 나타내면 아래와 같다.

자세히 설명하자면 컴퓨터 어플리케이션을 통해 데이터를 보낸다면 다음과 같은 순서의 과정을 겪을 것이다.
애플리케이션 데이터 생성
전송계층에서 TCP/UDP 헤더(포트) 추가 (세그먼트 생성)
네트워크 계층에서 IP 헤더 추가 (패킷 생성)
내부 네트워크면 ARP 테이블을 확인하여 목적지 IP의 MAC 주소 존재 여부 확인하고, 없으면 ARP를 통해 목적지 IP ARP 테이블 갱신.
외부 네트워크면 ARP 테이블의 기본 게이트웨이(다음 홉)의 MAC 주소 받아서 사용
ARP 테이블에서 다음 홉 MAC 주소를 이용하여 이더넷 헤더 추가(프레임 생성)
랜카드로 프레임 전달
랜카드는 다음 홉 MAC주소로 데이터 전달.
데이터 전달 중 목적지 주소 IP가 ARP 테이블에 존재하는 라우터가 존재하면 해당 ip에 최종적으로 전송.
하지만 클라이언트는 위 과정에서 서버 ip주소를 찾아야하는데 보통 도메인 주소를 입력한다. 그러면 어떻게 도메인 주소로 ip를 알아낼 수 있을까?? 예를 들면 yooncarrot.com의 443 포트로 https 통신을해야하는데 yooncarrot.com의 ip주소를 알아야 해당 서버에 접근할 수 있어야 한다. 이는 DNS를 통해 도메인 주소에 해당하는 ip주소를 받아오고 해당 ip주소로 https 통신을 했기 때문이다.
5. HTTP 버전
HTTP는 0.9, 1.0, 1.1, 2.0, 3.0 까지 나오면서 계속 발전하고 있다. 현재는 3.0 까지 나온 상태이며 1.1과 2.0 버전이 가장 빈번하게 사용되고 있다.
5.1 HTTP/0.9
HTTP/0.9는 HTTP 프로토타입이다. HTML 파일만 전송할 수 있었고 GET 메서드만 존재했다.
5.2 HTTP/1.0
처음으로 가장 널리 쓰인 버전이다. 버전 번호, Header, Method, MIME가 추가되었고 웹페이지 Form으로 상호작용할 수 있게되었다.
그리고 급격하게 WWW이 팽창하면서 keep-alive 커넥션, 가상 호스팅 지원, 프락시 연결 지원 등 많은 기능이 추가되었다.
keep-alive는 클라이언트와 서버간의 여러 요청과 응답을 하나의 tcp connection으로 처리할 수 있도록 만들었다. 그래서 매 요청마다 connection이 이루어지는 비용을 줄여 더 효율적으로 처리될 수 있도록 만들었다. 그리고 connection을 끊으려면 헤더에 Connection: close를 포함시켜 끊을 수 있도록 만들었다.(하나의 응답이 늦어지면 이후의 응답이 늦어지는 현상은 HOL blocking이라고 한다.)
5.3 HTTP/1.1
HTTP/1.1은 HTTP 설계의 구조적 결함 교정, 두드러진 성능 최적화, 잘못된 기능 제거에 집중되었고 더 복잡해진 웹 애플리케이션 배포를 지원한다.
keep-alive 기능을 default로 변경하였고 파이프라이닝 기능이 추가되었다.
파이프라이닝은 하나의 연결에서 여러 요청을 순차적으로 보내고 순차적으로 받을 수 있도록 해주는 기능이다. 응답 순서가 보장되어야하기 때문에 느린 응답 하나가 전체 응답을 지연시키기도 하지만 파이프라이닝 구현이 어렵기도 하고 프록시 서버가 제대로 처리하지 못해서 문제가 많아 지금 사용되지 않는다.
5.4 HTTP/2.0
HTTP/2.0은 데이터를 header와 body를 frame이라는 데이터 단위로 만들어 text가 아닌 binary화 하여 steam화 하여 보낸다. 그리고 multiplexing(멀티플렉싱)이라는 기능과 Server Push기능이 추가되었다.
HTTP/2.0은 요청마다 헤더를 1개나 2개의 header frame과 0개 이상의 data frame으로 나누어 1개의 stream으로 만들어 보낸다.
multiplexing(멀티플렉싱)은 HOL(Head of Line) Blocking를 해결하고자 생긴 기능이다. frame 단위로 데이터를 보내면서 3개의 요청이 있을 경우 꼭 순서대로 Header를 보내지 않고 3번째 요청의 Header보다 2번째 요청의 Header frame을 보낼 수 있도록 만들었기 때문에 요청 순서에 따라 응답이 순서대로 처리되는 현상을 개선했다.
물론 Application Layer에서는 극복되었지만 TCP Connection에서 frame을 주고 받았기 때문에 TCP에서 발생하는 HOL Blocking을 해결할 순 없었다. 예를 들면 중간에 어떤 Header의 패킷 손실이 있었다면 해당 손실된 패킬이 올 때까지 기다리는 동안 그 뒤에 받아야할 데이터들은 여전히 기다려야한다. Application Layer에서의 HOL Blocking은 해결했지만 Transport Layer에서의 HOL은 해결하지 못했다.
Server push는 클라이언트가 HTTP 요청하기 전에 서버가 먼저 클라이언트에 리소스를 보내는 것이다. 하지만 클라이언트는 서버가 보낸 리소스를 알지 못하고 다시 요청하기 때문에 이 기능은 제거되었다.
5.5 HTTP/3.0
HTTP/3.0에서는 Transport Layer에서 HOL Blocking 문제를 해결했다. 이를 해결하기 위해서 TCP에 의존하지 않고 UDP에 기반한 QUIC 프로토콜을 사용했다. 그래서 TCP에 기반한 Stream들이 UDP에 기반한 QUIC 프로토콜을 사용하여 각 스트림이 독립적이게 되었다. Connection을 맺는데 0초의 시간이 걸리게 되었다.
QUIC 프로토콜을 사용하게 되면서 각 요청 Stream이 독립적으로 작동할 수 있게 되었다. 쉽게 예를 들면 모든 요청들을 1개의 파이프를 통해서만 보내야 했다면, QUIC 프로토콜을 사용하면서 각 요청의 개수만큼의 파이프를 사용하여 요청을 보낼 수 있게된 것이다. 즉 패킷을 1개의 파이프가 아니라 여러 파이프로 보낼 수 있게 되었다.
QUIC 프로토콜은 TCP와 TLS 위에서 작동하지 않고 QUIC에서 통합 처리하기 때문에 지연이 매우 적다. QUIC은 UDP기반으로 동작하며 TLS 1.3이 내장되어 한 번 연결된 서버에 대해서는 재연결시 0-RTT(0 Round Trip Time)로 데이터를 바로 보낼 수 있다. 즉 핸드셰이크 없이 바로 데이터를 보낼 수 있어서 0-RTT로 데이터를 바로 보낼 수 있는 것이다.