사전 사유 구절
개념

사유 구절

gabury1고친 사람 github-actions[bot]

사유 구절은 응답의 결과 숫자를 사람이 읽는 말로 풀어 줍니다. 웹 서버가 보내는 응답의 첫 줄에서 결과 숫자 바로 뒤에 붙는 짧은 문구입니다. 「200 OK」의 OK 가 이것입니다. 프로그램은 이 문구를 안 보고 숫자만 보고 움직입니다.

쉽고 빠른 이해

사유 구절은 결과 숫자 옆에 붙는 사람용 설명입니다. 「404 Not Found」에서 Not Found 가 그것입니다.

숫자만 있으면 404 가 무슨 뜻인지 외워 둔 사람만 압니다. 로그를 들여다보는 개발자가 바로 알아보게 말을 붙였습니다. 프로그램은 숫자로 판단하므로 이 말이 바뀌어도 동작은 같습니다.

어떻게 도는가:

  1. 서버가 결과 숫자를 정합니다
  2. 숫자 뒤에 공백 하나를 두고 설명 문구를 적어 응답 첫 줄을 만듭니다
  3. 받는 프로그램은 숫자만 읽고 문구는 흘려보냅니다

대가가 있습니다. 이 문구는 믿을 수 있는 정보가 아닙니다. 중간에 거치는 서버가 바꾸거나 지울 수 있습니다. 새로 나온 버전의 웹 규약은 문구를 싣지 않습니다. 문구에 중요한 내용을 담으면 받는 쪽에 안 닿을 수 있습니다.

상세

학교 성적표에는 점수 옆에 선생님의 짧은 한마디가 함께 적히곤 합니다. 서류를 거르는 사람은 점수만 보고 판단합니다. 옆의 말은 점수를 처음 보는 사람이 감을 잡으라고 붙인 것입니다.

HTTP(HyperText Transfer Protocol, 하이퍼텍스트 전송 프로토콜)는 요청을 보내고 응답을 받는 규약입니다. 요청을 보내는 쪽을 클라이언트라고 부릅니다. 브라우저나 앱이 클라이언트입니다. 요청을 받아 처리하고 답하는 쪽은 서버입니다.

서버는 응답마다 결과를 세 자리 숫자로 알립니다. 이 숫자가 상태 코드입니다. 200 은 요청을 처리했다는 뜻입니다. 404 는 찾는 대상이 없다는 뜻입니다.

사유 구절은 이 숫자 뒤에 붙는 짧은 문구입니다. 영어로는 reason phrase 라고 부릅니다. 숫자가 무슨 뜻인지 사람이 바로 알아보게 덧붙인 말입니다.

앞의 성적표로 치면 점수가 상태 코드, 선생님의 한마디가 사유 구절입니다. 결과를 정하는 것은 언제나 숫자입니다. 사유 구절은 그 숫자를 풀어 쓴 설명이라서 숫자를 대신하지 못합니다.

상태 줄 안에서 놓이는 순서

서버가 찾는 대상이 없다고 답한 HTTP/1.1 응답 하나에서 사유 구절이 어디에 적히는지 봅니다.

http
HTTP/1.1 404 Not Found
Content-Type: text/plain; charset=utf-8
Content-Length: 9

not found

응답의 첫 줄을 상태 줄이라고 부릅니다. 그 아래 두 줄은 헤더입니다. 헤더는 본문의 형식과 길이를 알립니다. 빈 줄 다음이 응답 본문입니다.

상태 줄은 공백으로 나뉜 세 칸입니다. 맨 앞 칸은 이 응답이 어느 버전의 HTTP 로 쓰였는지 밝힙니다. 칸마다 담는 것과 읽는 쪽이 다릅니다.

칸 이 응답의 값 읽는 쪽
프로토콜 버전 HTTP/1.1 프로그램
상태 코드 404 프로그램
사유 구절 Not Found 사람

사유 구절은 상태 코드 뒤의 공백부터 줄 끝까지 이어집니다. Not Found 처럼 낱말 사이에 공백이 들어가도 괜찮습니다. 줄바꿈만은 못 넣습니다. 줄바꿈이 상태 줄이 끝났다는 표시이기 때문입니다.

숫자마다 붙은 대표 문구

HTTP 는 상태 코드마다 대표 문구를 하나씩 정해 두었습니다. 웹 프레임워크는 대개 숫자만 받고 문구는 이 표에서 골라 붙입니다. 백엔드 코드에서 숫자만 정하는 일이 흔한 까닭입니다.

상태 코드 대표 문구 뜻
200 OK 요청을 처리했다
201 Created 요청대로 새로 하나를 만들었다
301 Moved Permanently 주소가 영영 바뀌었다
404 Not Found 찾는 대상이 없다
500 Internal Server Error 서버 안에서 오류가 났다

이 문구는 권하는 값이지 정해진 값이 아닙니다. 서버는 다른 말로 바꿔도 됩니다. 사용자의 언어로 옮겨도 됩니다. 404 Nothing Here 라고 보내도 HTTP 로는 맞는 응답입니다.

문구를 비워도 됩니다. 그때도 숫자 뒤의 공백 하나는 반드시 남겨야 합니다. 문구 없는 상태 줄은 HTTP/1.1 404 처럼 공백으로 끝납니다.

HTTP/2 와 HTTP/3 에서 사라진 문구

HTTP/2와 HTTP/3는 HTTP/1.1 뒤에 나온 버전입니다. 같은 요청과 응답을 더 빠르게 나르려고 메시지를 글자 줄 대신 이진 형식으로 적습니다. 이진 형식은 사람이 읽는 글자가 아니라 기계가 읽는 바이트 구조입니다.

이 두 버전에는 상태 줄이 없습니다. 상태 줄의 칸 대신, 응답 앞머리에 이름표가 붙은 값이 따로 실립니다. 상태 코드는 :status 라는 이름표에 숫자만 담겨 갑니다. 이름 앞의 콜론은 보통 헤더와 구별하려고 붙인 표시입니다.

이 이름표들 가운데 사유 구절을 담는 것은 없습니다. 숫자는 그대로 건너가고 문구만 빠집니다.

브라우저 자바스크립트에서 HTTP 요청을 보낼 때는 Fetch API를 씁니다. API(Application Programming Interface)는 프로그램이 불러 쓰는 기능의 약속입니다. 응답을 받으면 status 로 상태 코드를, statusText 로 사유 구절을 읽습니다.

HTTP/2 이상으로 받은 응답에서는 statusText 가 빈 값입니다. 아래 코드는 사용자 하나를 요청해 404 를 받은 경우입니다. 같은 응답을 두 버전으로 받았을 때 무엇이 나오는지를 주석에 적었습니다.

JavaScript
const res = await fetch("/users/42");
res.status      // 404
res.statusText  // "Not Found" (HTTP/1.1)
res.statusText  // "" (HTTP/2)

같은 서버가 같은 404 를 보내도 버전에 따라 statusText 가 비어 버립니다. 숫자는 어느 버전에서나 같게 옵니다.

클라이언트가 문구를 믿지 않는 까닭

클라이언트는 사유 구절의 내용을 무시하는 편이 좋습니다. 문구가 서버를 떠난 모습 그대로 받는 쪽에 닿는다는 보장이 없기 때문입니다. 아래에서는 문구가 어떤 길로 달라지는지 봅니다.

응답은 서버에서 클라이언트로 곧장 가지 않을 때가 많습니다. 사이에 프록시가 끼기도 합니다. 프록시는 중간에서 요청과 응답을 대신 전달하는 서버입니다.

문구가 바뀌는 길은 셋입니다.

바뀌는 길 무슨 일이 생기나
사용자 언어로 옮김 서버가 사용자 언어에 맞춰 문구를 바꿔 보낸다
중간 서버가 고쳐 씀 프록시가 전달하면서 문구를 바꾼다
다른 버전으로 넘김 문구를 담을 칸이 없는 HTTP/2 로 옮기면서 버려진다

첫째 길은 서버가 스스로 고르는 일이지만 결과는 같습니다. 같은 404 라도 받는 사람마다 문구가 달라집니다. 문구를 읽어 판단하는 클라이언트는 사람마다 다르게 움직이게 됩니다.

아래 그림은 셋째 길을 보입니다. 서버가 HTTP/1.1 로 보낸 응답을 프록시가 HTTP/2 로 바꿔 브라우저에 넘깁니다.

sequenceDiagram
    participant 서버
    participant 프록시
    participant 브라우저
    서버->>프록시: HTTP/1.1 404 Nothing Here
    Note over 프록시: HTTP/2 로 바꿔 넘긴다
    프록시->>브라우저: 상태 404 · 문구 없음

서버가 고른 Nothing Here 는 브라우저에 닿지 않습니다. 숫자 404 는 남으므로 브라우저가 할 일은 달라지지 않습니다.

응답을 만드는 쪽에서 다루는 법

응답을 만드는 백엔드 쪽에서 지킬 것은 하나입니다. 문구에 정보를 싣지 않는 것입니다.

404 User 42 Not Found 처럼 문구에 사정을 적으면 HTTP/2 를 거치는 순간 사라집니다. 클라이언트가 그 문구를 읽어 분기하도록 짜 두었다면 버전이 바뀔 때 조용히 깨집니다.

사정을 알리려면 응답 본문에 적습니다. 본문은 어느 버전에서나 빠지지 않고 전달됩니다. 오류의 종류와 설명을 JSON(JavaScript Object Notation, 자바스크립트 객체 표기법) 한 덩이에 담아 보내는 방식이 흔합니다.

상태 코드를 알맞게 고르는 것이 먼저입니다. 실패를 200 으로 보내 놓고 문구로만 실패를 알리면 클라이언트도 중간 서버도 성공으로 읽습니다. 사유 구절은 웹 프레임워크가 붙이는 대표 문구를 손대지 않고 쓰면 됩니다.

HTTP 밖의 사유 구절

상태 줄 모양은 HTTP 밖에서도 쓰입니다. 인터넷 전화의 연결을 맺는 SIP(Session Initiation Protocol, 세션 시작 프로토콜)가 HTTP 의 응답 모양을 빌려 왔습니다.

SIP 도 응답 첫 줄에 버전, 세 자리 숫자, 사유 구절을 차례로 적습니다. 상대 전화기가 울리고 있다는 SIP 응답은 SIP/2.0 180 Ringing 입니다. 숫자가 결과를 정하고 문구는 사람을 위한 설명이라는 짜임도 HTTP 와 같습니다.

관련 항목

사유 구절과 함께 응답을 이루는 구성 요소

상태 줄 · 상태 코드 · 프로토콜 버전 · 헤더 · 응답 본문 · CRLF

사유 구절을 정의하는 규약과 문서

HTTP · HTTP 응답 · 메시지 · HTTP-1.1 · RFC 9110 · RFC 9112

사유 구절을 싣지 않는 다음 버전

HTTP-2 · HTTP-3 · 의사 헤더 · QUIC · 이진 프레이밍

대표 문구가 붙은 상태 코드

200 OK · 201 Created · 301 Moved Permanently · 404 Not Found · 500 Internal Server Error · 상태 코드 등급

사유 구절을 고쳐 쓰거나 버리는 중간 서버

프록시 · 역방향 프록시 · 로드 밸런서 · 게이트웨이 · CDN

사유 구절을 읽어 들이는 클라이언트 인터페이스

Fetch API · XMLHttpRequest · HTTP 클라이언트 · 브라우저

사유 구절 대신 사정을 전하는 수단

오류 응답 본문 · Problem Details · JSON · API 설계

같은 상태 줄 모양을 빌려 쓴 프로토콜

SIP · RTSP · ICAP

다른 이름: reason phrase · Reason-Phrase · reason-phrase · 상태 문구 · status text