HTTP 응답
고친 사람 github-actions[bot]
HTTP 응답은 서버가 요청을 어떻게 처리했는지 클라이언트에게 알려 줍니다. 처리 결과를 알리는 숫자와 결과물을 함께 실어 보냅니다. 클라이언트가 요청을 하나 보내면 서버는 응답을 하나 돌려줍니다.
쉽고 빠른 이해
무슨 일을 하는 물건인가 — 서버가 요청에 돌려주는 답장입니다. 클라이언트가 7번 사용자 정보를 달라고 하면, 서버는 「잘 처리했다」는 숫자 200 과 함께 그 사용자 정보를 담아 돌려보냅니다.
왜 이렇게 하나 — 클라이언트는 요청이 성공했는지부터 알아야 다음 행동을 고릅니다. 결과물만 오면 그것이 정상 결과인지 오류 안내문인지 가릴 수 없습니다. 그래서 결과를 먼저 숫자로 알립니다. 결과물은 뒤에 붙입니다.
어떻게 도나
- 첫 줄에 처리 결과를 숫자로 적습니다
- 그 아래 줄마다 결과물의 종류와 길이 같은 안내를 적습니다
- 빈 줄 하나를 두고 결과물을 붙여 보냅니다
대가 — 처리 결과를 적은 첫 줄과 안내 줄은 결과물보다 먼저 나갑니다. 결과물을 보내기 시작한 뒤에는 처리 결과 숫자를 바꿀 수 없습니다.
상세
이 절은 응답이 무엇으로 이루어지는지를 봅니다. 서버가 돌려준 응답 하나를 펼쳐 놓고 첫 줄부터 차례로 읽습니다. 끝에서는 백엔드 코드가 응답을 내보내는 순서와, 오류를 성공 코드에 담으면 생기는 일을 봅니다.
요청 하나에 응답 하나
HTTP(HyperText Transfer Protocol, 하이퍼텍스트 전송 프로토콜)는 웹에서 프로그램끼리 데이터를 주고받는 약속입니다. 주고받기는 언제나 클라이언트가 엽니다. 클라이언트가 HTTP 요청을 보내면 서버가 그 요청에 답하는 응답을 돌려줍니다.
서버는 요청 없이 먼저 응답을 보내지 않습니다. 요청 하나에는 최종 응답 하나가 짝을 이룹니다. 이렇게 묻고 답하는 한 쌍으로 대화가 굴러가는 방식을 요청-응답 모델이라고 부릅니다.
「최종」이라는 말을 붙인 까닭은 중간 응답이 있어서입니다. 중간 응답은 최종 응답 전에 서버가 먼저 보내는 짧은 안내입니다. 큰 요청 본문을 보내기 전에 헤더만 먼저 보낸 클라이언트에게 「요청 본문을 이어서 보내도 된다」고 알리는 것이 그 예입니다. 이 안내는 뒤의 상태 코드 표에서 1로 시작하는 코드로 다시 나옵니다.
응답을 이루는 세 부분
아래는 서버가 돌려준 응답 하나입니다. 클라이언트가 7번 사용자 정보를 달라고 요청했습니다. 서버가 그 사용자를 찾아 돌려준 결과입니다. HTTP 의 1.1 버전인 HTTP/1.1 은 응답을 이렇게 사람이 읽을 수 있는 글자로 적습니다.
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 26
{"id": 7, "name": "yuumi"}
방금 본 응답은 세 부분으로 나뉩니다. 첫 줄이 상태줄입니다. 그 아래 빈 줄 전까지가 헤더입니다. 빈 줄 다음이 본문입니다.
이 본문은 JSON(JavaScript Object Notation, 자바스크립트 객체 표기법)으로 적혀 있습니다. JSON 은 중괄호 안에 「이름: 값」 쌍을 늘어놓는 글자 형식입니다.
| 부분 | 무엇을 적나 | 이 응답에서는 |
|---|---|---|
| 상태줄 | HTTP 버전 · 처리 결과 숫자 · 짧은 설명 | HTTP/1.1 200 OK |
| 헤더 | 본문을 어떻게 다룰지 알리는 「이름: 값」 줄 | 본문은 JSON 이고 26바이트다 |
| 본문 | 요청한 결과물 | 7번 사용자 정보 |
관공서 창구에 신청서를 내면 처리 결과 통지서가 돌아옵니다. 맨 위에는 「처리 완료」나 「반려」 도장이 찍혀 있습니다. 그 아래 유의 사항 몇 줄 뒤에 발급된 서류가 붙어 있습니다. 도장이 상태줄, 유의 사항이 헤더, 붙은 서류가 본문입니다.
헤더와 본문 사이의 빈 줄은 경계 표시입니다. 받는 쪽은 빈 줄을 만나야 헤더가 끝났다는 것을 압니다. 그 뒤로 오는 바이트는 전부 본문으로 읽습니다.
상태 코드
상태줄의 가운데 숫자가 상태 코드입니다. 요청을 어떻게 처리했는지를 100 에서 599 사이의 숫자로 알립니다. 클라이언트 프로그램은 본문을 열기 전에 이 숫자부터 보고 다음 행동을 고릅니다.
맨 앞 숫자가 큰 갈래를 정합니다. 뒤의 두 숫자는 그 갈래 안의 세부를 정합니다. 그래서 처음 보는 코드를 받아도 맨 앞 숫자만 보면 성공인지 실패인지는 압니다. 아래 표가 다섯 갈래입니다.
| 맨 앞 숫자 | 갈래 | 흔히 보는 코드 |
|---|---|---|
| 1 | 정보. 최종 응답 전에 보내는 중간 안내 | 100 Continue |
| 2 | 성공 | 200 OK · 201 Created · 204 No Content |
| 3 | 리다이렉트. 다른 곳에서 찾아라 | 301 Moved Permanently · 304 Not Modified |
| 4 | 클라이언트 오류. 요청이 잘못됐다 | 400 Bad Request · [[HTTP 401 |
| 5 | 서버 오류. 요청은 맞는데 서버가 처리하지 못했다 | 500 Internal Server Error · 503 Service Unavailable |
1로 시작하는 코드가 앞에서 말한 중간 응답입니다. 나머지 네 갈래는 최종 응답입니다.
4와 5는 책임이 어느 쪽에 있느냐로 갈립니다. 4로 시작하면 같은 요청을 고치지 않고 다시 보내도 대개 같은 답이 옵니다. 5로 시작하면 서버 사정이 풀린 뒤 다시 보냈을 때 성공할 수 있습니다.
숫자 뒤의 OK 같은 글귀는 이유 문구입니다. 사람이 읽으라고 붙인 설명이라 프로그램은 이 글귀로 판단하지 않습니다. 같은 숫자에 다른 글귀를 적어 보내는 서버도 있습니다.
응답 헤더
헤더는 본문과 응답을 어떻게 다룰지 알리는 안내 줄입니다. 한 줄에 「이름: 값」 한 쌍을 적습니다. 백엔드 코드가 자주 채우는 응답 헤더는 아래 여섯입니다.
| 헤더 | 알리는 것 | 주로 붙는 응답 |
|---|---|---|
| Content-Type | 본문의 형식 | 본문이 있는 응답 |
| Content-Length | 본문의 바이트 수 | 본문 길이를 미리 아는 응답 |
| Cache-Control | 이 응답을 저장해 두고 다시 써도 되는지와 그 기간 | 다시 써도 되는 응답 |
| Set-Cookie | 클라이언트에 맡길 값 | 로그인을 처리한 응답 |
| Location | 옮겨 간 주소, 또는 새로 만든 것의 주소 | 3으로 시작하는 응답 · 201 |
| Retry-After | 얼마 뒤에 다시 보내면 되는지 | 503 |
표의 Set-Cookie 가 맡기는 값을 쿠키라고 부릅니다. 클라이언트는 쿠키를 저장해 두었다가 다음 요청마다 서버에 되돌려 보냅니다. 서버는 그 값으로 같은 사용자가 다시 왔음을 알아봅니다.
어떤 헤더는 특정 상태 코드와 짝을 이룹니다. 3으로 시작하는 응답은 대부분 Location 이 있어야 클라이언트가 어디로 갈지 압니다. 304 는 예외입니다. 가진 사본을 다시 쓰라는 답이라 갈 곳이 없습니다.
201 응답에도 Location 이 붙습니다. 이때는 방금 새로 만든 것의 주소를 가리킵니다. 503 응답은 Retry-After 로 언제 다시 보내면 될지를 알려 줍니다.
받는 쪽은 모르는 이름의 헤더를 만나면 그 줄을 건너뜁니다. 그래서 서버는 새 헤더를 더해도 옛 클라이언트를 깨뜨리지 않습니다.
본문
본문은 요청한 결과물입니다. JSON 한 덩이일 수도 있고 HTML(HyperText Markup Language, 하이퍼텍스트 마크업 언어) 문서나 이미지 파일일 수도 있습니다. 본문은 무엇이 들었는지 스스로 말하지 않습니다. Content-Type 헤더가 알려 줍니다.
본문이 없는 응답도 있습니다. 결과물 없이 처리 결과만 알리면 되는 경우입니다.
| 본문이 없는 응답 | 까닭 |
|---|---|
| HEAD 요청에 대한 응답 | HEAD 는 본문 없이 헤더만 달라는 요청이다 |
| 1로 시작하는 중간 응답 | 최종 응답 전에 보내는 안내뿐이다 |
| 204 No Content | 처리는 끝났고 돌려줄 결과물이 없다 |
| 304 Not Modified | 클라이언트가 가진 사본을 다시 쓰면 된다 |
204 는 삭제 요청처럼 돌려줄 결과물이 없는 처리에 흔히 씁니다. 처리가 끝났다는 것만 알리면 됩니다.
304 는 HTTP 캐시와 함께 쓰입니다. HTTP 캐시는 받은 응답을 저장해 두었다가 다시 쓰는 장치입니다. 클라이언트가 「내 사본이 아직 최신이냐」고 물으면 서버는 본문 없이 304 로 답합니다.
받는 쪽은 본문이 어디서 끝나는지 알아야 합니다. 서버가 길이를 미리 알면 Content-Length 에 적습니다.
미리 모르면 HTTP/1.1 은 본문을 조각으로 나눕니다. 조각마다 앞에 그 길이를 붙여 보냅니다. 마지막에는 길이가 0 인 조각을 보내 본문이 끝났음을 알립니다. 이 방식이 청크 전송 인코딩입니다.
버전마다 달라지는 겉모양
HTTP 에는 여러 버전이 있습니다. 앞에서 본 글자 모양은 HTTP/1.1 의 것입니다. 뒤를 이은 HTTP/2 와 HTTP/3 은 같은 응답을 이진 형식으로 바꿔 보냅니다. 이진 형식은 사람이 읽는 글자 대신 기계가 바로 읽는 바이트 배열로 적는 방식입니다.
이진 형식에는 상태줄이 따로 없습니다. 상태 코드는 :status 라는 특별한 헤더에 실립니다. 이유 문구는 보내지 않습니다. 헤더는 압축해서 보냅니다.
그래도 뜻은 바뀌지 않습니다. 어느 버전이든 응답은 상태 코드와 헤더와 본문으로 이루어집니다. 그래서 백엔드 코드는 어느 버전으로 나가든 이 셋만 채우면 됩니다.
응답이 나가는 순서
이 절은 응답이 어떤 순서로 나가는지를 봅니다. 그 순서 때문에 상태 코드가 언제 정해지는지도 봅니다. 큰 목록을 조금씩 보내다가 도중에 오류가 난 경우를 예로 듭니다.
백엔드 코드는 응답을 직접 바이트로 적는 일이 드뭅니다. 웹 프레임워크가 대신 적습니다. 웹 프레임워크는 요청을 받아 개발자가 짠 함수에 넘겨 주는 라이브러리입니다. 그 함수가 돌려준 값은 응답으로 바꿔 줍니다.
개발자가 짠 이 함수를 핸들러라고 부릅니다. 핸들러가 객체 하나를 돌려주면 프레임워크가 그것을 JSON 으로 바꿔 본문에 넣습니다. Content-Type 과 Content-Length 도 채웁니다. 상태 코드를 따로 정하지 않으면 대개 200 을 씁니다.
응답은 앞에서부터 나갑니다. 상태줄과 헤더가 먼저 나갑니다. 본문은 그 뒤를 따릅니다. 그래서 본문을 조금씩 내보내는 핸들러는 조심해야 합니다. 아래 그림은 큰 목록을 조각으로 보내다가 도중에 오류가 난 경우입니다.
sequenceDiagram
participant 클라이언트
participant 프레임워크
participant 핸들러
클라이언트->>프레임워크: 요청
프레임워크->>핸들러: 요청을 넘긴다
핸들러->>프레임워크: 본문 첫 조각
프레임워크->>클라이언트: 상태줄 200 · 헤더 · 첫 조각
Note over 클라이언트,프레임워크: 상태 코드는 이미 나갔다
핸들러->>프레임워크: 도중에 오류가 난다
프레임워크->>클라이언트: 연결을 끊는다
첫 조각이 나갈 때 200 도 함께 나갔습니다. 뒤늦게 오류가 나도 500 으로 바꿀 방법이 없습니다. 서버는 대개 연결을 끊습니다. 클라이언트는 본문이 끝까지 오지 않은 것을 보고 실패를 알아챕니다.
그래서 많은 프레임워크가 본문을 어느 정도 모아 두었다가 내보냅니다. 모으는 동안에는 아직 아무것도 나가지 않았으니 상태 코드를 바꿀 수 있습니다.
성공 코드에 담긴 오류
오류가 나도 상태 코드를 200 으로 두는 응답이 있습니다. 실패했다는 말은 본문에만 적습니다. 사람이 본문을 읽으면 실패인 줄 압니다. 상태 코드만 보는 프로그램은 이것을 성공으로 셉니다.
상태 코드만 보는 프로그램은 생각보다 많습니다. 모니터링 도구는 오류율을 상태 코드로 셉니다. 클라이언트의 재시도 로직은 5로 시작하는 코드를 보고 다시 보낼지를 정합니다.
캐시도 상태 코드를 봅니다. 304 에서 본 캐시는 클라이언트가 가진 사본이었습니다. 클라이언트와 서버 사이에 놓여 여러 클라이언트의 응답을 함께 저장하는 캐시도 있습니다. 이 캐시는 실패를 담은 200 응답을 저장해 두고 다른 클라이언트에게도 내줄 수 있습니다.
결과를 상태 코드로 알리면 이 프로그램들이 본문을 열지 않고도 성공과 실패를 가립니다. 실패의 자세한 사정은 본문에 적습니다.
관련 항목
HTTP 응답을 이루는 구성 요소
상태줄 · 상태 코드 · 이유 문구 · 헤더 · 본문 · 트레일러
HTTP 응답 첫 줄에 실리는 상태 코드
100 Continue · 200 OK · 201 Created · 204 No Content · 301 Moved Permanently · 304 Not Modified · 400 Bad Request · HTTP 401 · HTTP 403 · 404 Not Found · HTTP 429 · 500 Internal Server Error · 503 Service Unavailable
HTTP 응답에 실리는 헤더 필드
Content-Type · Content-Length · Cache-Control · Set-Cookie · 쿠키 · Location · WWW-Authenticate · Retry-After · ETag · Last-Modified
HTTP 응답을 불러내는 요청
HTTP 요청 · 요청 메서드 · 요청 대상 · GET · HEAD · POST · 조건부 요청
HTTP 응답 본문을 싣고 나르는 방식
청크 전송 인코딩 · 콘텐츠 협상 · JSON · HTML · 직렬화 · 스트리밍 · HTTP 압축
상태 코드를 보고 HTTP 응답을 다루는 장치와 로직
HTTP 캐시 · 캐싱 · 프록시 · 리버스 프록시 · CDN · 모니터링 · 재시도
HTTP 응답을 주고받는 역할
클라이언트 · 서버 · 웹 서버 · 브라우저 · 백엔드 · 웹 프레임워크 · 핸들러
HTTP 응답 형식을 정한 버전과 표준
HTTP/1.1 · HTTP/2 · HTTP/3 · RFC 9110 · RFC 9112
HTTP 응답을 재는 지표
응답 시간 · 지연 시간 · TTFB · 오류율 · 처리량
HTTP 응답을 비틀어 생기는 공격
HTTP 응답 스플리팅 · 헤더 인젝션 · 캐시 포이즈닝 · HTTP 요청 스머글링
HTTP 응답이 속하는 상위 분류
다른 이름: HTTP response · HTTP 응답 메시지 · 응답 메시지