GET
GET 은 웹에서 무언가를 받아 오라고 요청하는 방법입니다. 클라이언트가 주소 하나를 대고 그 자리의 현재 내용을 보내 달라고 말합니다. 받아 오기만 할 뿐 서버의 상태를 바꿔 달라고 요청하지는 않습니다.
쉽고 빠른 이해
GET 은 서버에게 "이 주소에 있는 걸 지금 내용 그대로 보내 달라"고 요청하는 방법입니다.
예를 들어 GET /hello.txt 라고 보내면 그 경로에 있는 파일 내용을 돌려받습니다.
GET 은 값을 읽기만 합니다. 서버 상태는 바꾸지 않습니다. 이 구분이 없으면 캐시가 응답을 안심하고 저장해 두지 못합니다. 링크를 따라가며 도는 자동 프로그램도 부작용을 걱정해야 합니다.
돌아가는 방식은 대략 이렇습니다.
- 클라이언트가 원하는 경로를 요청 첫 줄에 적어 보냅니다
- 서버가 그 자리의 내용을 찾으면 성공 표시(200)로 돌려줍니다. 못 찾거나 그 메서드를 안 받으면 404 나 405 같은 실패 코드로 답합니다
- 클라이언트가 이미 가진 저장본이 최신인지 물어보면 서버가 확인합니다. 안 바뀌었으면 그대로 쓰라는 표시(304)만 짧게 옵니다. 내용은 다시 안 보냅니다
요청에 내용을 실어도 GET 의 뜻은 안 바뀝니다. 그래서 보낼 데이터를 주소 안에 욱여넣기 쉽습니다. 그러면 남에게 보이면 안 될 값까지 주소에 그대로 드러날 수 있습니다. 그런 값을 보내야 할 때는 GET 대신 다른 메서드를 씁니다.
상세
GET 은 표적 리소스의 현재 선택된 표현을 전송해 달라고 요청하는 메서드입니다. RFC 9110(Request for Comments, 의견 요청) 9.3.1 이 그렇게 정의합니다. 표적 리소스는 요청이 겨냥하는 그 대상이고, 표현은 그 순간 그 대상이 실제로 돌려주는 데이터입니다. 식별자를 원격 파일 시스템의 경로로, 표현을 그 파일 내용의 복사본으로 생각하면 쉽습니다.
성공한 응답은 표적 URI(Uniform Resource Identifier, 통합 자원 식별자) 가 매번 같은 자원을 가리킨다는 동일성 성질을 그대로 반영합니다. 그래서 HTTP(HyperText Transfer Protocol, 하이퍼텍스트 전송 규약) 로 식별 가능한 정보를 가져오는 일은 대개 그 정보를 200 OK 응답으로 줄 가능성이 있는 식별자에 GET 요청을 보내는 방식으로 이뤄집니다.
실제로 많은 리소스가 파일 시스템 경로 그대로 구현돼 있습니다. 다만 실무에 그런 제한은 없습니다. 리소스의 HTTP 인터페이스는 콘텐츠 객체의 트리일 수도 있고, 여러 데이터베이스 레코드에 대한 프로그램적 관점일 수도 있고, 다른 정보 시스템으로 가는 게이트웨이일 수도 있습니다. URI 매핑이 파일 시스템에 묶여 있어도 오리진 서버(그 리소스를 실제로 갖고 응답을 만들어 내는 서버)는 요청을 입력 삼아 파일을 실행하고 그 출력을 표현으로 보내도록 설정될 수 있습니다. 각 식별자가 어느 구현에 대응하는지, 그리고 그 구현이 표적 리소스의 현재 표현을 어떻게 골라 보내는지는 오리진 서버만 알면 됩니다.
요청 메서드 토큰은 요청 의미의 주된 원천입니다. 클라이언트가 무엇을 하려고 이 요청을 보냈는지, 성공한 결과로 무엇을 기대하는지를 그 토큰이 가리킵니다. 명세는 GET 을 정보 검색의 주된 수단이자 거의 모든 성능 최적화의 초점이라고 적습니다. 중요한 리소스마다 URI 를 만드는 애플리케이션은 그 최적화의 혜택을 볼 수 있습니다.
표준화된 요청 메서드는 리소스별로 다르지 않습니다 — 이 성질이 균일 인터페이스이고, 균일 인터페이스는 네트워크 기반 시스템에서 가시성(겉에서 무엇이 일어나는지 알아보기 쉬움)과 재사용(다른 애플리케이션이 그대로 가져다 쓸 수 있음)을 낫게 만듭니다. 한번 정의된 표준 메서드는 어느 리소스에 적용하든 같은 의미를 가져야 합니다. 다만 그 의미를 구현할지 허용할지는 리소스마다 스스로 정합니다. 범용 서버는 GET 과 HEAD 를 반드시 지원해야 합니다. 나머지 메서드는 선택입니다.
형태
요청줄 · 요청 표적 · 상태줄이 각각 무엇으로 쪼개지는지 한 그림으로 모으면 이렇습니다.
flowchart TD
subgraph 요청["요청줄 request-line"]
M["method"]
RT["request-target"]
V1["HTTP-version"]
end
RT --> AP["absolute-path"]
RT --> Q["query"]
subgraph 응답["상태줄 status-line"]
V2["HTTP-version"]
SC["status-code"]
RP["reason-phrase"]
end
요청 -. 요청에 대한 응답 .-> 응답
요청줄은 메서드(method) · 요청 표적(request-target) · 버전(HTTP-version) 세 토막이고, 요청 표적은 다시 절대 경로(absolute-path) 와 질의(query) 로 쪼개집니다. 상태줄은 버전(HTTP-version) · 상태 코드(status-code) · 사유구(reason-phrase) 세 토막입니다. 아래는 이 조각들의 정확한 문법과 각 조각이 무엇을 뜻하는지입니다.
request-line = method SP request-target SP HTTP-version
요청줄은 메서드 토큰으로 시작해 공백 하나, 요청 표적, 다시 공백 하나, 프로토콜 버전으로 끝납니다.
메서드 자리에 GET 을 적습니다. 메서드 토큰은 대소문자를 구분합니다. 대소문자를 구분하는 메서드
이름을 가진 객체 기반 시스템으로 가는 게이트웨이가 될 수 있기 때문입니다. 표준 메서드는 관례상
전부 대문자 US-ASCII(American Standard Code for Information Interchange) 로 정의됩니다. 문법에서
메서드 자리는 token 규칙 하나로 정의됩니다 — 지금까지 써 온 「메서드 토큰」이 가리키는 것이 이
조각입니다.
method = token
요청 표적은 요청을 적용할 리소스를 가리킵니다. 클라이언트가 원하는 표적 URI 에서 요청 표적을 끌어냅니다. 형식은 넷입니다. origin-form · absolute-form · authority-form · asterisk-form 이고, 어느 것을 쓸지는 메서드와 프록시 여부가 정합니다. 오리진 서버로 곧장 보내는 GET 은 origin-form 입니다.
origin-form = absolute-path [ "?" query ]
표적 URI 의 절대 경로와 질의 요소만 요청 표적으로 보냅니다. 표적 URI 의 경로 요소가 비어 있으면
경로 자리에 / 를 반드시 보냅니다. 요청 표적에는 공백을 쓸 수 없습니다. HTTP/1.1 요청 메시지에는
Host 헤더 필드를 반드시 함께 보냅니다.
성공하면 200 OK 가 돌아옵니다. 200 응답의 콘텐츠는 표적 리소스의 표현입니다. 응답의 첫 줄은 상태줄입니다.
status-line = HTTP-version SP status-code SP [ reason-phrase ]
status-code = 3DIGIT
상태 코드는 서버가 요청을 이해하고 만족시키려 한 결과를 나타내는 세 자리 정수입니다. 뒤따르는 사유구는 선택입니다. GET 과 HEAD 에 대한 200 응답에서 오리진 서버는 선택된 표현이 그때와 같은지 나중에 비교할 수 있게 해 주는 검증자 필드를 보내야 합니다(SHOULD). 조금이라도 달라지면 값이 바뀌는 강한 엔티티 태그와 Last-Modified 날짜 둘 다가 선호됩니다.
의미를 바꾸는 헤더
요청 메서드의 의미는 함께 온 헤더 필드의 의미로 더 특수화될 수 있습니다. 그 추가 의미가 메서드와 충돌하지 않을 때에 한합니다.
| 헤더 | 무엇을 바꾸나 | 안 보내면 |
|---|---|---|
| Host | 바꾸지 않습니다. HTTP/1.1 요청에는 반드시 보냅니다 | 요청이 규칙을 어깁니다 |
| Range | 표현 전체가 아니라 하나 이상의 부분 범위만 전송하도록 메서드 의미를 바꿉니다 | 선택된 표현 전체가 옵니다 |
| If-None-Match | 요청을 조건부로 만듭니다. 조건이 거짓이면 GET 을 수행하지 않습니다 | 조건 없이 표현을 받습니다 |
Range 헤더 필드는 GET 요청에서 선택된 표현 데이터의 부분 범위만 요청하도록 메서드 의미를 수정합니다. 이 명세에서 범위 처리가 정의된 메서드는 GET 하나뿐입니다. 서버는 Range 헤더 필드를 무시해도 됩니다(MAY). 다만 오리진 서버와 중간 캐시는 가능하면 바이트 범위를 지원하는 편이 좋겠다고 명세가 적습니다. 부분적으로 실패한 전송에서 효율적으로 회복하고 큰 표현을 부분 조회하는 것을 받쳐주기 때문입니다.
Range 는 전제조건 헤더 필드를 먼저 평가한 다음에만 적용됩니다. 전제조건 헤더 필드에는 두 갈래가 있습니다. If-Match · If-None-Match · If-Range 는 가진 엔티티 태그와 일치하는 표현을 지목합니다. If-Modified-Since 는 가진 Last-Modified 날짜와 비교합니다. Range 가 없었다면 200 이 됐을 경우에만 평가됩니다. 조건부 GET 이 304 로 끝날 상황이면 Range 는 무시됩니다.
206 Partial Content 를 받으려면 조건을 전부 채워야 합니다. 전제조건이 모두 참이어야 합니다. 서버가
그 표적 리소스에서 Range 를 지원해야 합니다. 받은 Range 필드값이 그 리소스에서 지원되는
range-unit(범위를 세는 단위, 예: bytes)을 담은 유효한 범위 지정자여야 합니다. 지정자도 만족
가능해야 합니다. 이 조건을 모두 채우면 서버는 206 Partial Content 를 보내야 합니다(SHOULD).
If-None-Match 헤더 필드는 필드값이 * 일 때 수신 캐시나 오리진 서버가 표적 리소스의 현재 표현을
하나도 갖고 있지 않다는 조건을 겁니다. 엔티티 태그 목록이면 선택된 표현의 태그가 그중 어느 것과도
일치하지 않는다는 조건입니다. 약한 엔티티 태그는 표현 데이터가 뜻이 달라지지 않을 정도로만 바뀌어도
같다고 표시하도록 정의돼 있습니다. 그래서 약한 엔티티 태그도 표현 데이터가 바뀐 뒤의 캐시 검증에
쓸 수 있어야 합니다. 엔티티 태그를 비교할 때는 그런 변화가 있어도 같다고 봐주는 약한 비교 함수를
반드시 씁니다. 오리진 서버는 조건이 거짓으로 평가되면 요청한 메서드를 수행해서는 안 됩니다. 메서드가
GET 이나 HEAD 면 304 Not Modified 로 응답해야 합니다.
실패
요청줄이 도착한 뒤 GET 하나가 갈라지는 자리입니다.
flowchart TD
A{"메서드를 인식하고 구현했나"} -- 아니오 --> B["501 Not Implemented"]
A -- 예 --> C{"표적 리소스가 이 메서드를 허용하나"}
C -- 아니오 --> D["405 Method Not Allowed"]
C -- 예 --> E{"현재 표현을 찾았나"}
E -- 아니오 --> F["404 Not Found"]
E -- 예 --> G["200 OK"]
메서드를 알아보지 못하면 501 입니다. 알아봤지만 그 리소스에 허용되지 않으면 405 입니다. 메서드는 통과했는데 현재 표현이 없으면 404 입니다. 여기까지 지나야 200 이 나갑니다.
Range 를 붙인 요청은 이 200 자리에서 다시 갈립니다.
flowchart TD
A{"Range 요청인가"} -- 아니오 --> B["200 OK"]
A -- 예 --> C{"전제가 모두 참이고 서버가 Range 를 지원하나"}
C -- 아니오 --> B
C -- 예 --> D{"유효한 범위 지정자이고 range-unit 도 지원하며 만족 가능한가"}
D -- 예 --> E["206 Partial Content (SHOULD)"]
D -- 아니오 --> F["416 Range Not Satisfiable (SHOULD)"]
조건이 모두 맞으면 서버는 206 Partial Content 를 보내야 합니다(SHOULD). 조건은 맞지만 만족하는 범위가 하나도 없거나 서버가 그 range-unit 을 지원하지 않으면 416 Range Not Satisfiable 을 보내야 합니다(SHOULD).
| 조건 | 상태 코드 | 같이 오는 것 |
|---|---|---|
| 오리진 서버가 요청 메서드를 인식하지 못하고 어떤 리소스에 대해서도 지원할 수 없다 | 501 Not Implemented | 오리진 서버는 이 코드로 응답해야 합니다(SHOULD) |
| 구현한 어떤 메서드보다 긴 메서드 토큰을 받았다 | 501 Not Implemented | 서버는 이 코드로 응답해야 합니다(SHOULD) |
| 메서드는 오리진 서버가 알지만 표적 리소스가 지원하지 않는다 | 405 Method Not Allowed | 오리진 서버는 Allow 헤더 필드를 반드시 생성해야 합니다(MUST). 그 리소스가 지금 지원하는 메서드 목록이 들어갑니다 |
| 오리진 서버가 표적 리소스의 현재 표현을 찾지 못했거나 하나 있다는 사실을 밝힐 생각이 없다 | 404 Not Found | 없습니다. 조건이 영구적일 가능성이 높다고 알고 있으면 410 Gone 이 404 보다 선호됩니다 |
| Range 의 범위 집합이 하나도 만족되지 않는다. 또는 작거나 겹치는 범위를 지나치게 많이 요청했다 | 416 Range Not Satisfiable | 바이트 범위 요청이면 선택된 표현의 현재 길이를 담은 Content-Range 를 생성해야 합니다(SHOULD) |
| 파싱하려는 어떤 URI 보다 긴 요청 표적을 받았다 | 414 URI Too Long | 서버는 반드시 이 코드로 응답해야 합니다(MUST) |
| 요청줄이 유효하지 않다 | 400 Bad Request 또는 301 Moved Permanently | 수신자는 둘 중 하나로 응답해야 합니다(SHOULD). 301 이면 요청 표적을 제대로 인코딩해 돌려줍니다. 수신자는 리다이렉트 없이 자동 교정해 처리해서는 안 됩니다(SHOULD NOT) |
404 · 405 · 501 응답은 휴리스틱하게(정해진 규칙 없이 캐시가 스스로 판단해서) 캐시 가능합니다. 메서드 정의나 명시적 캐시 제어가 달리 지시하지 않는 한입니다. 실패 응답도 캐시에 남는다는 뜻입니다.
Allow 필드값이 비어 있으면 그 리소스가 아무 메서드도 허용하지 않는다는 뜻입니다. 설정으로 리소스가 일시적으로 비활성화된 405 응답에서 그런 일이 있을 수 있습니다. 허용 메서드 집합은 오리진 서버가 매 요청 시점에 정하므로 동적으로 바뀔 수 있습니다.
요청줄 길이에는 미리 정해진 한도가 없습니다. 실무에서는 갖가지 임시 한도가 발견됩니다. 명세는 모든 HTTP 송신자와 수신자가 최소 8000 옥텟의 요청줄을 지원할 것을 권장합니다.
성공했는데 원하는 게 안 된 경우
Range 를 보내도 서버는 그것을 무시할 수 있습니다. 그래서 많은 구현이 416 대신 선택된 표현 전체를 200 OK 로 돌려줍니다. 대부분의 클라이언트가 200 을 받아 일을 마칠 준비가 돼 있고, 완전한 표현을 받기 전에는 잘못된 범위 요청을 멈추지 않기도 하기 때문입니다. 명세는 클라이언트가 416 이 가장 적절한 상황에서조차 416 을 받는 데 의존할 수 없다고 적습니다.
조건부 GET 이 304 로 끝나면 표현 데이터가 오지 않습니다. 304 응답은 헤더 섹션의 끝에서 종료되며 콘텐츠도 트레일러도 담을 수 없습니다. 요청은 성공했지만 본문은 이번 왕복으로 오지 않고, 클라이언트가 이미 들고 있던 저장본(저장된 응답)을 쓰라는 지시가 옵니다.
예시
hello.txt 한 벌
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.
RFC 9110 3.9 가 http://www.example.com/hello.txt 에 대한 전형적인 HTTP/1.1 교환으로 든 것입니다.
요청줄 세 토막이 GET · /hello.txt · HTTP/1.1 로 나뉩니다. 응답 상태줄은 HTTP/1.1 · 200 ·
OK 입니다. ETag 와 Last-Modified 가 형태에서 말한 검증자 필드입니다. Accept-Ranges: bytes
는 이 표현에 바이트 범위 요청을 걸 수 있다는 표시입니다.
origin-form 요청 표적
GET /where?q=now HTTP/1.1
Host: www.example.org
http://www.example.org/where?q=now 로 식별되는 리소스의 표현을 오리진 서버에서 직접 받으려는
클라이언트가 보내는 두 줄입니다. 호스트 www.example.org 의 80 포트로 TCP(Transmission Control Protocol, 전송 제어 프로토콜) 연결을 열거나 재사용한
뒤 이 줄들을 보내고, 나머지 요청 메시지가 이어집니다. 표적 URI(http://www.example.org/where?q=now)
에서 스킴(http:)과 권한부(www.example.org)가 빠지고 절대 경로 /where 와 질의 ?q=now 만 요청
표적 자리에 남았습니다.
416 응답
HTTP/1.1 416 Range Not Satisfiable
Date: Fri, 20 Jan 2012 15:41:54 GMT
Content-Range: bytes */47022
RFC 9110 15.5.17 이 든 예입니다. bytes */47022 의 * 는 만족시킨 범위가 없다는 표시이고 47022 는
선택된 표현의 현재 길이입니다. 클라이언트는 이 길이를 보고 범위를 다시 정할 수 있습니다.
405 에 실리는 Allow
Allow: GET, HEAD, PUT
RFC 9110 10.2.1 의 사용 예입니다. Allow 필드는 표적 리소스가 지원한다고 광고하는 메서드 집합을 나열합니다. 이 필드의 목적은 그 리소스에 유효한 요청 메서드가 무엇인지 수신자에게 알리는 것으로 엄격히 한정됩니다.
If-None-Match 필드값
If-None-Match: "xyzzy"
If-None-Match: W/"xyzzy"
If-None-Match: "xyzzy", "r2d2xxxx", "c3piozzzz"
If-None-Match: W/"xyzzy", W/"r2d2xxxx", W/"c3piozzzz"
If-None-Match: *
RFC 9110 13.1.2 의 예 다섯 줄입니다. W/ 가 붙은 것이 약한 엔티티 태그입니다. 엔티티 태그를 가진
저장 응답을 갱신하려는 클라이언트는 GET 요청을 보낼 때 그 태그들을 나열한 If-None-Match 를
생성해야 합니다(SHOULD). 그래야 서버가 저장본 중 하나가 선택된 표현과 일치할 때 304 로 알려줄 수
있습니다.
보장과 가정
safe
보장 — GET 은 safe 메서드입니다. 정의된 의미가 본질적으로 읽기 전용이라는 뜻입니다. 클라이언트는 safe 메서드를 표적 리소스에 적용한 결과로 오리진 서버의 상태가 바뀌기를 요청하지도 기대하지도 않습니다. safe 메서드를 합리적으로 쓰는 것이 해나 재산 손실, 오리진 서버에 대한 이례적인 부담을 일으키리라 기대되지도 않습니다. 이 명세가 정의한 메서드 중 GET · HEAD · OPTIONS · TRACE(관례상 대문자로 쓴 trace, 추적) 가 safe 입니다.
가정 — 이 정의는 구현이 잠재적으로 해로운 동작, 완전히 읽기 전용은 아닌 동작, 부작용을 일으키는 동작을 포함하는 것을 막지 않습니다. 중요한 것은 클라이언트가 그 추가 동작을 요청하지 않았고 그에 대해 책임을 질 수 없다는 점입니다. 대부분의 서버는 메서드와 무관하게 응답이 끝날 때마다 액세스 로그 파일에 요청 정보를 덧붙입니다. 로그 저장소가 가득 차 서버가 실패할 수 있어도 그것은 safe 로 칩니다. 웹에서 광고를 골라 시작한 safe 요청이 광고 계정에 과금하는 부작용을 갖는 일도 흔합니다.
가정이 깨질 때 — 표적 URI 안의 파라미터가 동작을 고르도록 리소스를 만들었다면, 그 동작이 요청 메서드
의미와 일치하게 만드는 것은 리소스 소유자의 책임입니다. page?do=delete 처럼 질의 파라미터 안에
동작을 두는 웹 기반 콘텐츠 편집 소프트웨어가 흔합니다. 그런 리소스의 목적이 unsafe 동작이라면
소유자는 safe 요청 메서드로 접근됐을 때 그 동작을 반드시 비활성화하거나 불허해야 합니다. 그러지
않으면 링크 관리 · 프리페치 · 검색 색인 구축을 위해 모든 URI 참조에 GET 을 수행하는 자동화
프로세스(링크를 따라가며 도는 자동 프로그램)가 불행한 부작용을 일으킵니다. safe 와 unsafe 를 가르는
목적 자체가 그런 자동화 프로세스(스파이더라고도 부릅니다)와 프리페치 같은 캐시 성능 최적화가 해를 끼칠 걱정
없이 돌게 하는 데 있습니다.
idempotent
보장 — GET 은 멱등성(idempotent) 이 있습니다. 그 메서드로 동일한 요청을 여러 번 보냈을 때 서버에 대한 의도된 효과가 한 번 보냈을 때와 같다는 뜻입니다. 이 명세가 정의한 메서드 중 PUT · DELETE 와 safe 메서드가 idempotent 이고, GET 은 safe 이므로 여기 듭니다.
가정 — safe 의 정의와 마찬가지로 멱등성은 사용자가 요청한 것에만 적용됩니다. 서버는 요청마다 따로 로그를 남기거나 리비전 관리 기록을 유지하거나 다른 비멱등 부작용을 구현해도 자유입니다.
이 보장이 쓰이는 자리 — 클라이언트가 서버의 응답을 읽기 전에 통신 실패가 나면 요청을 자동으로 되풀이할 수 있습니다. 되풀이해도 의도된 효과가 같다는 것을 알기 때문입니다. 응답은 다를 수 있습니다.
sequenceDiagram
participant 클라이언트
participant 서버
클라이언트->>서버: GET 요청 (연결 1)
Note over 클라이언트,서버: 응답이 오기 전에 연결이 끊김
클라이언트->>서버: 같은 GET 요청 (새 연결)
서버-->>클라이언트: 응답
연결이 끊긴 시점이 응답을 읽기 전이라는 게 핵심입니다. 응답을 이미 받았다면 그 요청은 끝난 것이고 되풀이할 이유가 없습니다. 프록시는 비멱등 요청을 자동으로 재시도해서는 안 됩니다(MUST NOT). 클라이언트는 실패한 자동 재시도를 다시 자동으로 재시도해서는 안 됩니다(SHOULD NOT).
캐시 가능
보장 — GET 요청에 대한 응답은 캐시 가능합니다. 캐시는 그 응답을 뒤따르는 GET 과 HEAD 요청을 만족시키는 데 써도 됩니다(MAY).
가정 — Cache-Control 헤더 필드가 달리 지시하지 않는 한입니다. 캐시가 응답을 저장해 쓰려면 해당 메서드가 캐싱을 명시적으로 허용해야 합니다. 또한 어떤 조건에서 뒤따르는 요청을 만족시킬 수 있는지를 상술해야 합니다. 그렇게 하지 않은 메서드 정의는 캐시될 수 없습니다. 이 명세는 GET · HEAD · POST 에 캐싱 의미를 정의합니다. 다만 압도적 다수의 캐시 구현은 GET 과 HEAD 만 지원합니다.
가정이 깨질 때 — 캐시가 요청한 URI 에 대해 저장된 응답(저장본)을 하나 이상 갖고 있지만 그중 어느 것도 제공할 수 없으면, 조건부 요청 메커니즘으로 검증에 들어갑니다. 저장된 응답에 엔티티 태그가 있었다면 캐시는 If-Match · If-None-Match · If-Range(Range 를 적용하는 전제조건으로 쓰이는 헤더) 중 해당하는 것으로 그 태그를 반드시 보내야 합니다.
sequenceDiagram
participant 캐시
participant 서버
캐시->>서버: 조건부 요청 (If-Match / If-None-Match / If-Range)
alt 저장본이 아직 맞음
서버-->>캐시: 304 Not Modified
Note over 캐시: 저장된 응답을 갱신해 재사용
else 저장본이 안 맞음
서버-->>캐시: 완전한 응답
Note over 캐시: 그 응답으로 저장본을 교체
end
콘텐츠가 담긴 완전한 응답이 오면 조건부 요청에 지명한 저장본 중 적합한 것이 없다는 뜻입니다. 캐시는 그 완전한 응답으로 요청을 만족시켜야 합니다(MUST).
경계
GET 요청에 본문을 실으면 그것도 GET 인가. GET 입니다. 다만 그 본문은 GET 의 의미 밖입니다.
요청 메시지 프레이밍은 사용된 메서드와 독립입니다. 그래서 GET 요청에 콘텐츠를 담는 것 자체를 프레이밍 규칙이 막지는 않습니다. 판정의 근거는 그다음 문장입니다. GET 요청으로 받은 콘텐츠에는 일반적으로 정의된 의미가 없습니다. 그 콘텐츠는 요청의 뜻이나 표적을 바꿀 수 없습니다. 표적을 정하는 것은 요청 표적이고 본문이 아닙니다.
싣고 나서 벌어질 수 있는 일도 명세가 적습니다. 일부 구현은 요청 스머글링 공격(중개자마다 요청의 경계를 다르게 해석해 생기는 보안 취약점)이 될 소지 때문에 그 요청을 거부하고 연결을 닫을 수 있습니다. 클라이언트는 그런 요청이 목적을 갖고 충분히 지원된다고 오리진 서버가 대역 내(HTTP 요청· 응답 자체)로든 대역 밖(사적 합의 같은 그 통신 밖의 경로)으로든 미리 밝힌 경우가 아니면, 오리진 서버로 직접 보내는 GET 요청에 콘텐츠를 생성해서는 안 됩니다(SHOULD NOT). 오리진 서버도 콘텐츠를 받으려고 사적 합의에 기대서는 안 됩니다(SHOULD NOT). HTTP 통신 참여자는 요청 사슬을 따라 놓인 중개자를 모르는 경우가 많기 때문입니다.
그래서 데이터를 요청 콘텐츠로 보내야 하는 자리는 GET 이 아닙니다. 폼의 질의 필드처럼 사용자가 준 정보로 표적 URI 를 조립하는 방식으로 정보 검색을 하면, URI 안에 공개하기에 적절하지 않은 민감한 데이터가 실릴 수 있습니다. 어떤 경우에는 그 데이터를 걸러 내거나 변환해 그런 정보를 드러내지 않게 할 수 있습니다. 다른 경우, 특히 응답을 캐시해서 얻을 이점이 없을 때는 GET 대신 POST 를 써서 그 정보를 표적 URI 가 아니라 요청 콘텐츠로 보낼 수 있습니다.
관련 항목
이웃 메서드
HEAD · POST · PUT · DELETE · OPTIONS · TRACE
속한 규격
HTTP · 요청 메서드 · RFC 9110 · RFC 9111 · RFC 9112
딸린 보장과 개념
safe · 멱등성(idempotent) · 캐싱 · 검증자 · 엔티티 태그 · Cache-Control · 상태 코드
주고받는 상대
다른 이름: GET 메서드 · 겟