RFC 9110
웹의 요청과 응답이 무엇을 뜻하는지를 정해 놓은 표준 문서입니다. 어떤 요청이 무엇을 뜻하고 어떤 응답 코드가 무슨 결과를 가리키는지를 이 문서가 정합니다. 바이트를 어떤 모양으로 주고받는지는 버전마다 다른 문서가 맡습니다.
쉽고 빠른 이해
RFC 9110 은 웹 요청과 응답이 무슨 뜻인지 정해 놓은 문서입니다. GET 요청이 무엇을 요구하는 것인지, 404 응답이 무엇을 알리는 것인지를 이 한 문서가 못박습니다.
이걸 안 정해 두면 버전마다(1.1·2·3) 메서드와 응답 코드의 뜻을 따로 적어야 합니다. 그러면 같은 GET 요청이 버전마다 다른 뜻으로 읽힐 위험이 생깁니다.
돌아가는 방식은 이렇습니다.
- 요청 메서드·응답 코드·필드 이름처럼 모든 버전이 공유하는 뜻을 이 문서 한 편에 모읍니다
- 그 뜻을 실제로 어떤 바이트 모양으로 주고받는지는 정하지 않고 각 버전 문서(1.1·2·3 판)에 넘깁니다
- 예전에 여러 문서에 흩어져 있던 정의를 이 문서 한 편으로 모으면서 옛 문서 아홉 편을 폐기합니다
대가도 있습니다. 이 문서만 읽어서는 실제 통신이 어떻게 이뤄지는지 알 수 없습니다. 연결을 어떻게 맺고 메시지를 어디서 끊는지는 따로 각 버전 문서를 봐야 합니다.
상세
RFC(Request for Comments) 9110 은 「HTTP Semantics」라는 제목을 단 문서입니다.
HTTP(HyperText Transfer Protocol, 하이퍼텍스트 전송 프로토콜)의 전체 구조를 서술하고, 공통 용어를
세우고, 모든 버전이 공유하는 부분을 정의합니다. 그 정의 안에 핵심 프로토콜 요소와 확장 장치가 들어가고,
http 와 https URI(Uniform Resource Identifier) 스킴도 여기서 정해집니다. 스킴은 URI 맨
앞에 붙어 나머지를 어떻게 해석할지 정하는 이름표입니다.
이 문서는 HTTP 를 상태를 안 가지는 응용 계층(전송 계층 위에서 애플리케이션이 직접 주고받는 층입니다) 요청/응답 프로토콜의 가족으로 규정합니다. 가족 구성원이 공유하는 것이 셋입니다. 자원이 무엇이든 같은 방식으로 다루는 균일한 인터페이스, 확장 가능한 의미론(요청과 응답이 각각 무슨 뜻인지를 정하는 부분입니다), 메시지 하나만 봐도 그것을 어떻게 다뤄야 하는지 알 수 있는 스스로 설명하는 메시지입니다. 서비스를 어떻게 구현했는지는 클라이언트에게 내미는 그 균일한 인터페이스 뒤에 가려집니다. 서버도 마찬가지로 클라이언트 각자의 목적을 알 필요가 없습니다. 요청 하나를 특정 종류의 클라이언트나 정해진 순서의 애플리케이션 단계(이전 요청들이 쌓아 온 순서를 서버가 기억해 두고 그 순서를 따라야만 받아주는 방식)에 묶지 않고 따로 떼어 판단할 수 있습니다.
여기서 이 문서의 범위가 나옵니다. 인터페이스 뒤에서 무슨 일이 벌어지는지로는 프로토콜을 정의할 수 없습니다. 그래서 정의할 수 있는 것이 셋으로 제한됩니다. 통신의 구문(메서드 토큰이나 필드 이름처럼 요청·응답을 이루는 조각 하나하나가 따르는 문법입니다. 그 조각들을 바이트로 어떻게 이어 붙여 보내는지 — 뒤에서 「메시지 구문」이라 부를 그것 — 는 이것과 다른 층이고 이 문서가 정하지 않습니다. 그건 뒤의 「경계」가 다룹니다), 받은 통신의 의도(그 요청이나 응답을 보낸 쪽이 무엇을 하려 했는지), 그리고 수신자에게 기대되는 행동입니다.
의미론의 본체는 메시지입니다. 클라이언트가 자기 의도를 담은 요청 메시지를 만들어 원 서버(그 자원을 실제로 갖고 있어 요청이 최종적으로 향하는 서버)로 보내고, 서버는 그 메시지를 파싱해 대상 자원에 비추어 해석한 뒤 응답 메시지로 답합니다. 클라이언트는 돌아온 상태 코드와 콘텐츠를 보고 자기 의도가 수행됐는지 판단합니다. 이 왕복에서 조각마다 무슨 뜻인지를 문서가 절 단위로 나눠 맡습니다. GET 이 무엇을 요구하는지, 200 이 무엇을 뜻하는지가 그렇게 정해집니다.
| 절 | 무엇의 뜻을 정하나 |
|---|---|
| §5 Fields | 확장 가능한 이름/값 쌍인 필드입니다. 필드 이름의 이름공간은 등록해 관리합니다 |
| §9 Methods | 요청 메서드 토큰입니다. 클라이언트가 왜 이 요청을 보냈는지, 성공하면 무엇을 기대하는지 — 요청 뜻의 대부분이 여기서 나옵니다 |
| §11 HTTP Authentication | 도전-응답(서버가 클라이언트에게 인증 정보를 요구하고 클라이언트가 그 정보로 답하는 방식) 인증 스킴의 일반 틀 |
| §12 Content Negotiation | 자원이 여러 모습(표현 — 같은 자원을 형식·언어·인코딩만 다르게 담은 버전들)으로 존재할 때 그 가운데 무엇을 내려보낼지 고르는 선택 알고리즘 |
| §13 Conditional Requests | 메서드를 적용하기 전에 시험할 전제 조건과 그 우선순위 |
| §14 Range Requests | 표현의 일부만 다시 받아 이어 붙이는 요청 |
| §15 Status Codes | 세 자리 정수 코드. 유효한 값은 100 부터 599 까지입니다 |
출처 문서
이 절은 이 문서의 정체 — 번호·상태·저자, 요구 강도 낱말을 읽는 법, 폐기·갱신 관계 — 를 정합니다. 정본은 rfc-editor.org 가 내는 RFC 9110 원문이고, 문서 머리가 번호와 상태를 함께 적습니다.
Internet Engineering Task Force (IETF) R. Fielding, Ed.
Request for Comments: 9110 Adobe
STD: 97 M. Nottingham, Ed.
Obsoletes: 2818, 7230, 7231, 7232, 7233, 7235, Fastly
7538, 7615, 7694 J. Reschke, Ed.
Updates: 3864 greenbytes
Category: Standards Track June 2022
ISSN: 2070-1721
HTTP Semantics
번호는 9110, 발행은 2022년 6월입니다. 분류(문서가 어떤 절차를 거쳐 표준이 되는지 나타내는 갈래입니다)는 Standards Track(정식 표준화 절차를 밟는 문서라는 뜻입니다) 입니다. 표준 번호로 STD 97 을 달았습니다. IETF(Internet Engineering Task Force)가 내고 편집자는 세 사람입니다. R. Fielding, M. Nottingham, J. Reschke 입니다.
요구 강도
MUST · MUST NOT · REQUIRED · SHALL · SHALL NOT · SHOULD · SHOULD NOT · RECOMMENDED · NOT RECOMMENDED · MAY · OPTIONAL. 이 낱말들은 BCP(Best Current Practice) 14, 즉 RFC 2119 와 RFC 8174 가 정의한 대로 해석됩니다. 조건이 붙어 있습니다. 전부 대문자로 적혔을 때만, 그리고 그때만 그렇게 해석합니다. 소문자로 쓰인 같은 낱말은 요구 강도가 아닙니다.
MUST 는 어기면 표준을 안 지킨 것이고, SHOULD 는 이유가 있으면 어겨도 됩니다. 이 차이를 뭉개면 명세를 잘못 읽은 것입니다.
요구가 누구에게 걸리는지도 이 절이 정합니다. 이 명세는 HTTP 통신에서 맡은 역할에 따라 적합성 기준을 겁니다(어떤 요구를 지켜야 그 역할을 제대로 하는 것인지를 역할별로 갈라 정한다는 뜻입니다). 그래서 요구는 발신자, 수신자, 클라이언트, 서버, 사용자 에이전트, 중개자, 원 서버, 프록시, 게이트웨이, 캐시 가운데 그 행동이 제약되는 쪽에 놓입니다. 통신 하나의 범위를 넘어서는 요구는 구현체, 자원 소유자, 프로토콜 요소 등록(메서드·필드 이름처럼 프로토콜에 새 요소를 추가할 때 따르는 등록 절차)에 따로 걸립니다.
폐기 관계
이 문서 한 편이 아홉 편을 폐기했습니다. 검색은 대개 옛 판을 먼저 물어옵니다. RFC 7231 의 절 번호를 인용하면 폐기된 판을 근거로 드는 것입니다.
| 폐기된 문서 | 제목 |
|---|---|
| RFC 2818 | HTTP Over TLS(Transport Layer Security) |
| RFC 7230 | HTTP/1.1 Message Syntax and Routing (일부만) |
| RFC 7231 | HTTP/1.1 Semantics and Content |
| RFC 7232 | HTTP/1.1 Conditional Requests |
| RFC 7233 | HTTP/1.1 Range Requests |
| RFC 7235 | HTTP/1.1 Authentication |
| RFC 7538 | HTTP Status Code 308 (Permanent Redirect) |
| RFC 7615 | HTTP Authentication-Info and Proxy-Authentication-Info Response Header Fields |
| RFC 7694 | HTTP Client-Initiated Content-Encoding |
RFC 7230 만 갈라져 있습니다. HTTP/1.1 메시지 구문과 연결 관리에서 독립적인 부분만 9110 이 폐기하고, 남은 부분은 RFC 9112 가 폐기합니다. 그리고 9110 은 RFC 3864 를 갱신합니다.
flowchart TD
R9110["RFC 9110"] -->|폐기| Others["RFC 2818 · 7231 · 7232 · 7233<br/>7235 · 7538 · 7615 · 7694"]
R9110 -->|폐기: 메시지 구문과 무관한 부분| R7230["RFC 7230"]
R9112["RFC 9112"] -->|폐기: 메시지 구문·연결 관리 부분| R7230
R9110 -->|갱신| R3864["RFC 3864"]
모든 화살표가 같은 방향(폐기하거나 갱신하는 문서 → 그 대상 문서)을 가리키고, 라벨만 관계를 가릅니다. RFC 7230 만 화살표를 둘 받습니다 — 절반은 9110 이, 나머지 절반은 9112 가 폐기합니다.
예시
메시지 한 벌
§3.9 가 http://www.example.com/hello.txt 에 대한 GET 요청의 전형적인 HTTP/1.1 교환을 싣습니다.
GET /hello.txt HTTP/1.1
User-Agent: curl/7.64.1
Host: www.example.com
Accept-Language: en, mi
HTTP/1.1 200 OK
Date: Mon, 27 Jul 2009 12:28:53 GMT
Server: Apache
Last-Modified: Wed, 22 Jul 2009 19:15:56 GMT
ETag: "34aa387-d-1568eb00"
Accept-Ranges: bytes
Content-Length: 51
Vary: Accept-Encoding
Content-Type: text/plain
Hello World! My content includes a trailing CRLF.
요청 줄의 GET 은 §9 가 정한 메서드 토큰이고, 응답 첫 줄의 200 은 §15 가 정한 상태 코드입니다.
그 아래 ETag · Accept-Ranges · Vary 도 필드입니다 — §5 가 정한 이름/값 쌍 형식을 따르는 실물입니다.
GET 의 정의
§9.3.1 이 GET 메서드를 이렇게 정합니다. GET 은 대상 자원의 현재 선택된 표현을 전송해 달라는 요청입니다. 성공 응답은 그 대상 URI 가 가리키는 "같음" 이라는 성질을 반영합니다 — 같은 URI 로 다시 요청해도 같은 자원의 표현이 돌아온다고 봐도 된다는 뜻입니다. 이 "같음" 을 정확히 무엇으로 규정할지는 URI 명세가 따로 정하고, 이 문서는 거기로 미룹니다.
실제로 쓰이는 방식은 이렇습니다. HTTP 로 식별 가능한 정보를 가져올 때는, 그 정보를 200 응답으로 내줄 가능성이 있는 식별자에 GET 요청을 겁니다.
메서드 이름이 무엇을 뜻하는지가 여기서 못 박힙니다. 구현이 정하는 것이 아닙니다.
404 Not Found 의 정의
§15.5.5 가 404 를 이렇게 정합니다. 원 서버가 대상 자원의 현재 표현을 찾지 못했거나, 그런 표현이 존재한다는 사실을 밝힐 의사가 없다는 뜻입니다. 404 는 그 표현 없음이 일시적인지 영구적인지를 가리키지 않습니다. 원 서버가 그 상태가 영구적일 가능성이 높다고 안다면 404 보다 410 Gone 이 선호됩니다. 원 서버가 그렇게 안다면, 그 앎은 대개 어떤 설정 가능한 수단을 통해서일 것입니다. 그리고 404 응답은 휴리스틱하게(서버의 명시적 지시 없이 캐시가 제 나름의 판단 규칙으로) 캐시될 수 있습니다. 다만 메서드 정의나 명시적 캐시 제어가 달리 지시하면 그렇지 않습니다.
문서가 뜻을 정할 때 한정어까지 함께 정한다는 것을 보여주는 자리입니다. "찾지 못했다" 와 "밝힐 의사가 없다" 가 같은 코드에 묶여 있고, 영구성 판단은 코드 밖으로 밀려나 있습니다.
배경
HTTP 는 1990년에 등장한 뒤로 웹의 주된 정보 전송 프로토콜이었습니다. 시작은 사소한 장치였습니다. 메서드가 GET 하나뿐이었고, 주어진 경로 이름으로 식별되는 하이퍼텍스트 문서를 달라고 하는 것이 전부였습니다. 웹이 커지면서 요청과 응답을 메시지 안에 감싸고, MIME(Multipurpose Internet Mail Extensions)을 닮은 미디어 타입으로 임의의 데이터 형식을 나르고, 중개자를 거쳐 요청을 라우팅하는 기능이 붙었습니다. HTTP/1.1 은 기존 텍스트 기반 메시지 구문 (바이트를 어떤 모양으로 주고받는지 정하는, 앞서 「상세」가 통신의 구문과 갈라 둔 그 메시지 구문입니다)과의 호환을 유지한 채 기능을 다듬은 판입니다. 길이 기반 데이터 구분자, 콘텐츠 협상의 일관된 틀, 조건부 요청을 위한 불투명 검증자(값 자체의 뜻은 몰라도 이전 값과 같은지 다른지만 비교하면 되는 조건부 요청용 표지입니다), 캐시 제어, 범위 요청, 기본 지속 연결이 이때 들어왔습니다.
HTTP/1.1 은 1995년에 처음 나왔고, 1997년에 Standards Track 문서(RFC 2068)로 정식 발행됐습니다. 1999년에 한 차례 개정됐고(RFC 2616), 2014년에 RFC 7230 부터 7235 까지로 다시 개정됐습니다. 판올림 연혁은 이렇습니다.
timeline
title HTTP 의미론이 RFC 9110 한 편으로 모이기까지
1990 : HTTP 등장 — 메서드 GET 하나로 하이퍼텍스트 문서만 주고받음
1995 : HTTP/1.1 도입
1997 : Standards Track 문서로 처음 발행
1999 : 개정
2014 : RFC 7230~7235 로 다시 개정
2022 : RFC 9110 발행 — 의미론을 메시지 구문에서 떼어 냄
그다음 두 버전은 전송 쪽을 갈아 끼웠습니다. HTTP/2 는 기존 TLS 와 TCP(Transmission Control Protocol) 위에 다중화(하나의 연결로 여러 요청과 응답을 동시에 주고받는 방식입니다) 세션 계층(그 연결이 열려 있는 동안의 상태를 관리하는 층입니다)을 얹었고, HTTP/3 는 QUIC 을 TCP 대신 UDP(User Datagram Protocol) 위의 보안 다중화 전송으로 씁니다. 그런데 세 주요 버전 모두 이 문서가 정의하는 의미론에 기댑니다. 서로를 폐기하지도 않았습니다. 쓰임새의 맥락에 따라 각자 이점과 한계가 다르기 때문입니다. 구현은 자기 맥락에 가장 알맞은 전송과 메시지 구문을 고르게 되어 있습니다.
여기서 필요가 나왔습니다. 이번 개정은 의미론의 정의와 캐싱의 정의를 현행 HTTP/1.1 메시지 구문에서 떼어 냈습니다. 각 주요 버전이 같은 핵심 의미론을 참조하면서 따로 나아갈 수 있게 하려는 것입니다. 그 결과로 남은 의미론 몫이 RFC 9110 「HTTP Semantics」입니다.
경계
요청 줄이 어디서 시작해 어디서 끝나는지도 이 문서가 정하나. 아닙니다. §6.1 이 메시지 프레이밍은 HTTP 의 각 주요 버전이 자기 것을 정의한다고 못 박습니다. 프레이밍은 메시지가 같은 연결 위의 다른 메시지나 잡음과 구분되도록 시작과 끝을 가리키는 장치입니다. HTTP/0.9 와 초기 HTTP/1.0 은 밑에 깔린 연결을 닫는 것으로 응답을 끝냈고, 호환을 위해 이 암묵적 프레이밍은 HTTP/1.1 에서도 허용됩니다. 다만 암묵적 프레이밍은 연결이 일찍 닫혔을 때 불완전한 응답을 구분하지 못할 수 있습니다. 그래서 거의 모든 현대 구현은 길이로 구분되는 명시적 프레이밍을 씁니다.
버전 번호 자체도 이 선을 따릅니다. §2.5 에 따르면 앞자리인 주 버전이 메시지 구문을 가리키고, 뒷자리 숫자는 보내는 쪽이 앞으로의 통신에서 어디까지 알아들을 수 있다고 스스로 보장하는지 그 상한을 가리킵니다. 핵심 의미론은 버전 사이에 바뀌지 않지만, 그것을 "on the wire" — 앞서 말한 메시지 구문, 흔히 와이어 포맷이라 부르는 것 — 로 표현하는 방식은 바뀔 수 있습니다. 그래서 와이어 포맷에 호환되지 않는 변경이 생기면 버전 번호가 올라갑니다. 그 결과 "HTTP/1.1" 이라는 버전은 이 문서 하나로 정의되지 않습니다. 이 문서와, 캐시와 캐시 동작을 정하는 HTTP Caching(아래 표의 RFC 9111)과, HTTP/1.1 의 메시지 구문을 정하는 HTTP/1.1 명세(아래 표의 RFC 9112)를 합친 것이 그 버전입니다.
| 9110 이 안 정하는 것 | 정하는 문서 |
|---|---|
| 캐시와 캐시 동작을 제어하는 헤더 필드 | RFC 9111 |
| HTTP/1.1 의 메시지 구문 · 파싱 · 연결 관리 | RFC 9112 |
| HTTP/2 의 필드 압축과 한 연결 위의 동시 교환 | RFC 9113 |
| HTTP 의미론을 QUIC 위로 옮기는 매핑 | RFC 9114 |
관련 항목
이 문서가 속한 프로토콜과 발행처
같은 개정에서 나눠 맡은 문서
RFC 9111 · RFC 9112 · RFC 9113 · RFC 9114
이 문서가 폐기하거나 갱신한 문서
RFC 2818 · RFC 7230 · RFC 7231 · RFC 7232 · RFC 7233 · RFC 7235 · RFC 7538 · RFC 7615 · RFC 7694 · RFC 3864
이 문서가 뜻을 정하는 프로토콜 요소
요청 메서드 · 상태 코드 · 필드 · 인증 · 콘텐츠 협상 · 조건부 요청 · 범위 요청
요구 강도 낱말
MUST · MUST NOT · REQUIRED · SHALL · SHALL NOT · SHOULD · SHOULD NOT · RECOMMENDED · NOT RECOMMENDED · MAY · OPTIONAL · BCP · RFC 2119 · RFC 8174
이 정의를 쓰는 버전
다른 이름: HTTP Semantics · STD 97