도입 — 브라우저와 서버의 HTTP 대화를 읽는다
URL 을 입력한 뒤 일어나는 일(DNS → TCP → TLS → HTTP) 속에서 HTTP 의 위치를 확인하고, 리퀘스트와 리스폰스의 생 텍스트 뼈대, 그리고 스테이트리스의 의미를 파악한다.
Network 탭을 열었지만, 어디를 봐야 할지 모르겠다
페이지가 표시되지 않는다, API 가 기대대로 움직이지 않는다 — 선배에게 상담하면 「개발자 도구의 Network 탭을 봐」라는 말을 듣습니다. 열어 보면 행과 숫자가 잔뜩 늘어서 있어서, 어디서부터 읽어야 할지 모르겠다. 만들기 시작한 지 얼마 안 된 무렵, 누구나 한 번은 지나는 장면입니다.
사실 그 화면에 비치는 것의 정체는 매우 소박합니다. 브라우저와 서버는 텍스트로 쓰인 편지를 1 왕복씩 주고받고 있을 뿐입니다. 브라우저가 「이것을 주세요」라는 편지(리퀘스트)를 보내고, 서버가 「네, 결과는 이랬습니다」라는 편지(리스폰스)를 돌려준다. 이 왕복 서신의 서식만 알면, Network 탭도 curl 의 출력도 같은 뼈대로 읽을 수 있게 됩니다.
이 강좌에서는 어떤 출력을 볼 때든 같은 3 가지를 확인합니다.
HTTP 가 시작되기 전에 — URL 입력에서 일어나는 일
브라우저에 https://example.com/ 을 입력하고 Enter 를 누르면, HTTP 의 편지가 보내지기 전에 몇 가지 준비가 겹겹이 쌓입니다.
example.com 이라는 이름에서 서버의 IP 주소를 조회합니다. 받는 곳의 주소를 모르면 편지는 부칠 수 없습니다http:// 라면 이 단계는 생략되고, 편지는 평문 그대로 흐릅니다중요한 것은 층의 분담입니다. DNS 는 주소 담당, TCP 는 수송 담당, TLS 는 봉투 담당이고, HTTP 는 편지의 본문 그 자체입니다. HTTPS 가 되어도 편지의 서식(이 강좌에서 배우는 모든 것)은 변하지 않습니다 — 봉투에 들어가는지 아닌지가 다를 뿐입니다.
리퀘스트와 리스폰스는 방향이 반대일 뿐, 뼈대는 같은 「1 행째 + 헤더 + 빈 줄 + 바디」입니다. 1 행째만 역할에 따라 형태를 바꿉니다 — 부탁하는 쪽은 리퀘스트 행, 답하는 쪽은 상태 행.
생 텍스트를 읽어 본다
실제 1 왕복을 가공하지 않고 그대로 봅니다. 먼저 브라우저가 보내는 리퀘스트입니다.
GET /docs/index.html HTTP/1.1
Host: example.com
Accept: text/html
1 행째가 리퀘스트 행입니다. GET(무엇을 하고 싶은가 = 메서드), /docs/index.html(무엇에 대해서인가 = 경로), HTTP/1.1(어느 판으로 이야기하는가 = 버전)의 3 가지를 공백으로 구분해 나열합니다. 2 행째부터는 이름: 값 형태의 헤더가 이어지고, 빈 줄이 「여기까지가 머리말」이라는 신호가 됩니다. GET 의 리퀘스트는 부탁만 하는 것이므로, 빈 줄 뒤의 바디는 비어 있습니다.
서버가 보내는 리스폰스도 같은 뼈대로 돌아옵니다.
HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Content-Length: 1256
<!DOCTYPE html>
<html>...
1 행째는 상태 행입니다. 200 이 기계를 위한 3 자리 결과 코드, OK 는 사람을 위한 보조 문구. 이어지는 헤더가 「HTML 입니다·1256 바이트입니다」라는 보충을 곁들이고, 빈 줄 뒤에 부탁받은 것(HTML 본문)이 바디로 도착합니다.
여기가 강좌 전체의 토대입니다: 리퀘스트도 리스폰스도 「1 행째 + 헤더 + 빈 줄 + 바디」. 1 행째를 읽으면 「무엇을 부탁했는가」「결과는 어땠는가」를 알 수 있고, 헤더를 읽으면 「조건과 보충」을 알 수 있습니다.
연습 1-1 — URL 입력에서 HTTP 까지의 여정
HTTP 가 시작되기 전에 무엇이 일어나는지, 그리고 리퀘스트 1 행째를 읽는 법을 확인합니다.
Q1. 브라우저에 https://example.com/ 을 입력한 뒤, HTTP 리퀘스트가 전송되기까지 일어나는 일의 순서로 올바른 것은 어느 것입니까.
편지를 보내려면 먼저 주소(DNS 로 IP 주소를 조회), 다음으로 길(TCP 접속), HTTPS 라면 봉투의 봉인(TLS)이 필요하며, HTTP 의 대화는 그 위에서 시작됩니다. HTTP 리퀘스트를 가장 먼저 보낼 수는 없고(보낼 곳을 아직 모르므로), TLS 는 TCP 위에 만들어지므로 TCP 보다 먼저 오지 않습니다. 이 강좌에서 읽는 것은 이 겹겹의 층 가장 위에 있는 층입니다.
Q2. 리퀘스트의 1 행째 GET /docs/index.html HTTP/1.1 을 읽는 법으로 올바른 것은 어느 것입니까.
리퀘스트 행은 「동사 + 목적어 + 사용 언어의 판」입니다. GET 이 무엇을 하고 싶은가(가져오고 싶다), /docs/index.html 이 무엇에 대해서인가, HTTP/1.1 이 어느 판의 HTTP 로 이야기하는가. 상태 코드는 리스폰스 쪽의 1 행째에 나타나는 것으로, 리퀘스트 행에는 포함되지 않습니다. 이 3 가지 조합을 읽을 수 있으면 「무엇을 부탁했는가」는 반드시 알 수 있습니다.
Q3. HTTP 의 리퀘스트나 리스폰스에서, 헤더의 끝과 바디의 시작을 구분 짓는 것은 어느 것입니까.
헤더를 1 행씩 적어 내려간 뒤 빈 줄을 1 개 두면 「여기서부터는 바디입니다」라는 신호가 됩니다. 편지로 치면, 머리말 뒤에 1 행을 비우는 것과 같은 역할입니다. END 같은 종단 기호나 특별한 바이너리는 없습니다 — HTTP/1.1 의 메시지는 끝까지 텍스트의 약속으로 읽을 수 있습니다.
스테이트리스 — 서버는 「아까의 계속」을 기억하지 않는다
이 왕복 서신에는 초심자가 처음에 놀라는 성질이 있습니다. 서버는 원칙적으로 이전 리퀘스트를 기억하지 않습니다. 1 통째에서 상품 페이지를 보고, 2 통째에서 장바구니에 넣어도, 서버에게 2 통째는 「모르는 사람에게서 온 새 편지」입니다. 이것을 스테이트리스(상태를 갖지 않음)라고 부릅니다.
불편해 보이지만, 이것은 설계상의 선택입니다. 리퀘스트마다 완결되어 있기 때문에, 서버는 1 통씩 독립적으로 처리할 수 있고, 몇 대에든 분담시킬 수 있습니다. 세계 규모의 서비스가 성립하는 것은 이 결단 덕분입니다.
그렇다면 로그인 상태 같은 「이어지는 이야기」는 어떻게 실현하는가. 답은 매번의 편지에 이름표를 곁들이는 것입니다 — 서버가 발행한 표식(Cookie)을, 브라우저가 이후의 리퀘스트에 매번 적어 곁들입니다. 구조는 제 4 장에서 읽지만, 「스테이트리스한 왕복 서신 위에, 곁들임 메모로 상태를 만든다」는 구도만 먼저 가지고 계세요.
연습 1-2 — 리스폰스 읽는 법과 스테이트리스
돌아온 쪽의 1 행째와, HTTP 의 중요한 성질 「스테이트리스」를 확인합니다.
Q4. 리스폰스의 1 행째 HTTP/1.1 200 OK 에 포함된 200 과 OK 의 설명으로 올바른 것은 어느 것입니까.
상태 행은 「버전 + 3 자리 상태 코드 + 사람을 위한 문구」입니다. 프로그램이 판정에 사용하는 것은 200 이라는 숫자 쪽이고, OK 는 읽는 사람을 위한 곁들임 메모에 지나지 않습니다. 결과의 판정은 이 3 자리로 한다 — 이것이 3 점 세트의 두 번째 「결과는 어땠는가」를 읽는 법이며, 제 3 장에서 자릿수별로 깊이 파고듭니다.
Q5. HTTP 는 「스테이트리스」라고 합니다. 이 설명으로 올바른 것은 어느 것입니까.
스테이트리스(state-less)는 「상태를 갖지 않는다」— 리퀘스트마다 완결되며, 서버는 「아까의 계속」을 자동으로는 기억하지 않습니다. 그렇기 때문에 각 리퀘스트에는 필요한 정보를 매번 곁들여야 하고, 로그인 상태 같은 「이어지는 이야기」를 실현하려면 제 4 장에서 다루는 Cookie 라는 곁들임 메모의 구조를 사용합니다. 암호화나 동시 접속 수의 이야기가 아닙니다.
이 장에서 가져갈 것
- HTTP 는 DNS → TCP → TLS 의 준비 위에서 오가는 텍스트의 왕복 서신이다
- 리퀘스트도 리스폰스도 뼈대는 같은 「1 행째 + 헤더 + 빈 줄 + 바디」. 1 행째는 리퀘스트 행(메서드·경로·버전) 또는 상태 행(버전·3 자리 코드·문구)
- HTTP 는 스테이트리스 — 각 리퀘스트는 독립된 1 통. 「이어지는 이야기」는 Cookie 등의 곁들임 메모로 만든다
- 읽는 법은 언제나 3 점 세트 — 무엇을 부탁했는가·결과는 어땠는가·조건과 보충은 무엇인가
다음 장에서는 3 점 세트의 첫 번째, 「무엇을 부탁했는가」를 깊이 파고듭니다. GET 과 POST 는 어떻게 다른가, 그리고 「다시 보내도 되는 부탁」은 어느 것인가 — 메서드의 약속을 읽습니다.