합동회사 코무라소프트
1장

도입 — 브라우저와 서버의 HTTP 대화를 읽는다

URL 을 입력한 뒤 일어나는 일(DNS → TCP → TLS → HTTP) 속에서 HTTP 의 위치를 확인하고, 리퀘스트와 리스폰스의 생 텍스트 뼈대, 그리고 스테이트리스의 의미를 파악한다.

Network 탭을 열었지만, 어디를 봐야 할지 모르겠다

페이지가 표시되지 않는다, API 가 기대대로 움직이지 않는다 — 선배에게 상담하면 「개발자 도구의 Network 탭을 봐」라는 말을 듣습니다. 열어 보면 행과 숫자가 잔뜩 늘어서 있어서, 어디서부터 읽어야 할지 모르겠다. 만들기 시작한 지 얼마 안 된 무렵, 누구나 한 번은 지나는 장면입니다.

사실 그 화면에 비치는 것의 정체는 매우 소박합니다. 브라우저와 서버는 텍스트로 쓰인 편지를 1 왕복씩 주고받고 있을 뿐입니다. 브라우저가 「이것을 주세요」라는 편지(리퀘스트)를 보내고, 서버가 「네, 결과는 이랬습니다」라는 편지(리스폰스)를 돌려준다. 이 왕복 서신의 서식만 알면, Network 탭도 curl 의 출력도 같은 뼈대로 읽을 수 있게 됩니다.

이 강좌에서는 어떤 출력을 볼 때든 같은 3 가지를 확인합니다.

1. 무엇을 부탁했는가
메서드와 경로 — 리퀘스트 행을 읽는다(이 장과 제 2 장)
2. 결과는 어땠는가
상태 코드 — 리스폰스 1 행째의 3 자리를 읽는다(제 3 장)
3. 조건과 보충은 무엇인가
헤더 — 형식·양·조건 등의 곁들임 메모를 읽는다(제 4〜5 장)

HTTP 가 시작되기 전에 — URL 입력에서 일어나는 일

브라우저에 https://example.com/ 을 입력하고 Enter 를 누르면, HTTP 의 편지가 보내지기 전에 몇 가지 준비가 겹겹이 쌓입니다.

Step 1 — DNS: 주소를 알아본다
example.com 이라는 이름에서 서버의 IP 주소를 조회합니다. 받는 곳의 주소를 모르면 편지는 부칠 수 없습니다
Step 2 — TCP: 길을 잇는다
그 IP 주소와의 사이에, 빠뜨림 없이 바이트열을 나를 수 있는 접속을 확립합니다. 편지를 확실하게 전달하는 우편망입니다
Step 3 — TLS: 봉인한다(https 의 경우)
경로 위에서 읽히거나 고쳐 쓰이지 않도록, 암호화된 통신로를 만듭니다. http:// 라면 이 단계는 생략되고, 편지는 평문 그대로 흐릅니다
Step 4 — HTTP: 편지를 쓴다(이 강좌의 주역)
준비가 갖춰진 통신로 위에서, 비로소 「이것을 주세요」라는 텍스트 편지가 보내집니다

중요한 것은 층의 분담입니다. DNS 는 주소 담당, TCP 는 수송 담당, TLS 는 봉투 담당이고, HTTP 는 편지의 본문 그 자체입니다. HTTPS 가 되어도 편지의 서식(이 강좌에서 배우는 모든 것)은 변하지 않습니다 — 봉투에 들어가는지 아닌지가 다를 뿐입니다.

리퀘스트(리퀘스트 행·헤더·빈 줄·바디)와 리스폰스(상태 행·헤더·빈 줄·바디)가 같은 뼈대를 가진다는 것을 나타낸 HTTP 메시지 구조도

리퀘스트와 리스폰스는 방향이 반대일 뿐, 뼈대는 같은 「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 리퀘스트가 전송되기까지 일어나는 일의 순서로 올바른 것은 어느 것입니까.

Q2. 리퀘스트의 1 행째 GET /docs/index.html HTTP/1.1 을 읽는 법으로 올바른 것은 어느 것입니까.

Q3. HTTP 의 리퀘스트나 리스폰스에서, 헤더의 끝과 바디의 시작을 구분 짓는 것은 어느 것입니까.

스테이트리스 — 서버는 「아까의 계속」을 기억하지 않는다

이 왕복 서신에는 초심자가 처음에 놀라는 성질이 있습니다. 서버는 원칙적으로 이전 리퀘스트를 기억하지 않습니다. 1 통째에서 상품 페이지를 보고, 2 통째에서 장바구니에 넣어도, 서버에게 2 통째는 「모르는 사람에게서 온 새 편지」입니다. 이것을 스테이트리스(상태를 갖지 않음)라고 부릅니다.

불편해 보이지만, 이것은 설계상의 선택입니다. 리퀘스트마다 완결되어 있기 때문에, 서버는 1 통씩 독립적으로 처리할 수 있고, 몇 대에든 분담시킬 수 있습니다. 세계 규모의 서비스가 성립하는 것은 이 결단 덕분입니다.

그렇다면 로그인 상태 같은 「이어지는 이야기」는 어떻게 실현하는가. 답은 매번의 편지에 이름표를 곁들이는 것입니다 — 서버가 발행한 표식(Cookie)을, 브라우저가 이후의 리퀘스트에 매번 적어 곁들입니다. 구조는 제 4 장에서 읽지만, 「스테이트리스한 왕복 서신 위에, 곁들임 메모로 상태를 만든다」는 구도만 먼저 가지고 계세요.

연습 1-2 — 리스폰스 읽는 법과 스테이트리스

돌아온 쪽의 1 행째와, HTTP 의 중요한 성질 「스테이트리스」를 확인합니다.

Q4. 리스폰스의 1 행째 HTTP/1.1 200 OK 에 포함된 200OK 의 설명으로 올바른 것은 어느 것입니까.

Q5. HTTP 는 「스테이트리스」라고 합니다. 이 설명으로 올바른 것은 어느 것입니까.

이 장에서 가져갈 것

  • HTTP 는 DNS → TCP → TLS 의 준비 위에서 오가는 텍스트의 왕복 서신이다
  • 리퀘스트도 리스폰스도 뼈대는 같은 「1 행째 + 헤더 + 빈 줄 + 바디」. 1 행째는 리퀘스트 행(메서드·경로·버전) 또는 상태 행(버전·3 자리 코드·문구)
  • HTTP 는 스테이트리스 — 각 리퀘스트는 독립된 1 통. 「이어지는 이야기」는 Cookie 등의 곁들임 메모로 만든다
  • 읽는 법은 언제나 3 점 세트 — 무엇을 부탁했는가·결과는 어땠는가·조건과 보충은 무엇인가

다음 장에서는 3 점 세트의 첫 번째, 「무엇을 부탁했는가」를 깊이 파고듭니다. GET 과 POST 는 어떻게 다른가, 그리고 「다시 보내도 되는 부탁」은 어느 것인가 — 메서드의 약속을 읽습니다.