선언문은 무엇에 관한 것인지 알려주지만, 제어는 언급하지 않는 곳에 있다.
요약
본 글은 API 응답의 캐싱(caching)과 관련된 '선언문(declaration)'과 실제 '제어(control)' 메커니즘을 구분하는 방법을 설명합니다. 특히, HTTP Vary 헤더가 무엇에 관한 것인지를 알려줄 뿐, 실제로 어떤 값이 제어권을 가지는지까지는 명시하지 않는다는 점을 지적합니다.
핵심 포인트
- 선언문은 응답이 '무엇에 관한 것인지'를 알려주지만, 실제 '제어권'은 알려주지 않는다.
- 캐싱 관점에서 중요한 것은 헤더(header)가 아닌 필드(field)의 빈 값(empty value)일 수 있다.
- API 설계 시, 명시된 축 외에 예상치 못한 값이 캐시 동작을 제어할 수 있으므로 주의해야 한다.
선언문은 무엇에 관한 것인지 알려주지만, 제어는 언급하지 않는 곳입니다.
Vary: Accept-Encoding, Origin, X-Loggedin은 한 가지 선언문(declaration)입니다. 이 선언문은 다음과 같이 말합니다: 이 응답은 이 세 축을 따라 다를 수 있으므로, 캐시가 이를 키로 사용해야 한다.
이 해석은 정확하지만, 동시에 함정이기도 합니다. 저는 이 줄을 제가 사용할 수 있는 레버(levers)의 목록으로 취급하며 시간을 보냈습니다. 즉, 이름 붙여진 세 개의 축이 있었으므로 엣지에서 새로운 답변을 얻는 세 가지 방법이 있다고 생각했죠. 하지만 그중 두 가지는 작동하지 않았고, 실제로 작동한 것은 이 줄에 아예 없습니다.
이것은 일반적인 형태에 관한 것입니다: 선언문은 그것이 무엇에 관한 것인지 알려줍니다. 제어(control)가 어디 있는지 알려주지는 않습니다. 이것들은 서로 다른 질문이며, 답하기 쉬운 쪽이 오해를 불러일으킬 가능성이 높습니다.
세 개의 축이 이름 붙여져 있습니다. 하나는 당신의 것입니다.
공개 API, 하나의 URL, 1분 동안, 제가 보낸 헤더에 따라 응답만 다릅니다:
GET /api/comments?a_id=… Vary: Accept-Encoding, Origin, X-Loggedin
(추가 헤더 없음) HIT, HIT Age 29,243 etag W/"5282e2ed…"
...
Origin은 답변을 변경시킵니다: 제가 한 번도 보내지 않은 값이 요청 시점에 생성된 응답에 포함되었고, 이 값은 오래된 복사본에는 없던 댓글을 담고 있었습니다.
X-Loggedin은 그렇지 않습니다. 그리고 실패가
제어(The control)는 쿠키 이름이며, 아무것도 그것을 선언하지 않는다
그가 세션 쿠키—존재하지 않는 가짜 값, 존재하지 않는 사용자—를 보냈고 캐시는 완전히 건너뛰었다. 나는 이를 재현했고, 어떤 부분이 작업을 수행하는지 찾아보았다:
(쿠키 없음) MISS, HIT Age 30 Cache-Control: public, no-cache
Cookie: remember_user_token=zz1 MISS, MISS Age - Cache-Control: max-age=0, private, must-revalidate
Cookie: remember_user_token= MISS, MISS Age - Cache-Control: max-age=0, private, must-revalidate
...
세 번째 줄이 내가 예상하지 못했던 부분이다. 빈 값(empty value)이 가짜 값과 정확히 같은 역할을 한다. remember_user_token=에 대한 세션 조회가 이루어지면 그것을 거부해야 한다—거기에는 세션이 없으므로—따라서 취해지는 분기는
일반화는 캐시(cache)에 관한 것이 아니므로, 여기서는 산문으로 동일한 결함이 있습니다. 이는 동료 심사 저널의 자체 편집 규정에서 발견되었는데, 여기서 오류가 발생한 부분은 헤더(header)가 아니라 필드(field)였습니다.
모든 투고는 기여 수준을 선언합니다: '사례 연구(case study)', '시스템(system)', 또는 '이론+실증(theory+empirics)'입니다. 한 패키지는 이 수준을 세 가지 매체—등록의 목표, 원고문의 선언, 그리고 패키지의 README.md—에 명시하고, 세 사람이 이를 읽습니다: 품질 기준(항목 7), 저자의 투고 체크리스트, 그리고 심사위원의 '기여 수준 일관성(Contribution-level consistency)' 행입니다.
수정되기 전에는 이 세 가지 매체 모두 필드를 **증거(evidence)**와만 관련지었습니다. 각 매체는 올바랐습니다. 그들이 볼 수 없었던 결함은 심사에서 발견되었습니다: 한 패키지의 README.md는 '이론+실증'이라고 했지만, 원고문에는 '실증'이라고 되어 있었습니다. 모든 매체는 증거와 일관되지만, 두 사본(copy)은 아무것도 비교하지 않고 읽혔습니다. 두 가지 수준을 선언하는 패키지는 그 필드에 대해 작성된 모든 테스트를 통과합니다—왜냐하면 각 테스트가 하나의 사본과 하나의 피연산자(operand)를 명시하고, 불일치는 사본들 사이의 것이기 때문입니다.
수정은 수준을 증거와 더 잘 비교하는 것이 아니었습니다. 그것은 각각의 매체에 두 번째 피연산자를 부여하는 것이었습니다: 매체를 명명하고, 사본들을 먼저 서로 비교한 다음, 비로소 하나를 증거와 비교하는 것입니다. 저널 자체 용어로 말하자면, 인구 조사(census)는 3개 매체 중 사본을 명시하는 경우가 0건에서 3건으로 바뀌었고, 저는 이를 확인하기 위해 세 가지 매체를 처음부터 다시 읽었습니다 (세 곳 모두 명시하고 있습니다; 커밋 61af779에 이전/이후 내용이 담겨 있습니다).
두 필드, 두 매체, 하나의 형태: 무언가가 무엇에 관한 것인지 나열한 목록과 그 목록에서 벗어난 제어(control)입니다. 헤더는 캐시 키가 적용된 축을 명명했고; 쿠키는 저장소를 관리했습니다. 규칙은 각 독자가 가지고 있는 피연산자를 명명했고; 불일치가 존재하는 형제 사본(sibling copy)은 아무도 명명하지 않았습니다.
제가 얻은 교훈
선언(declaration)은 무엇에 관한 것인지 목록을 보여줄 뿐이지, 제어(control)를 알려주지는 않습니다. 결과값을 변경해야 할 때는
위에 인용된 저널은 제가 작업하는 오픈 소스 GitHub 기반 CS 저널인 silicon-science-cs입니다. 기여 수준 규칙(contribution-level rule)은 이 기록의 커밋 61af779에 있으며, 저는 이것을 작성하기 전에 33524f9에서 세 가지 캐리어(carriers)를 다시 읽어보았습니다. HTTP 번호는 한 호스트의 하나의 API에 대한 외부 관찰이며, 쿠키 레버를 발견한 독자는 스레드 자체에서 공로를 인정받습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기