
지난 글에서 HTTP는 메시지를 기반으로 통신한다고 하였다. 메시지는 오직 요청/응답 두가지만 있으며, 머리-가슴-배 시작줄-헤더-본문으로 구성되는 것또한 살펴봤다. 요청, 응답은 시작줄에 각기 다른 내용을 갖는 다는 것 또한 확인했다.
이제 메시지의 구성 요소들과 각 요소들의 옵션들을 상세히 정리해볼 차례이다. 한번 쯤은 정리하고 넘어가도 좋을 내용이라 궁금한 건 더 찾아보면서 작성했다.
메시지의 흐름
- HTTP 메시지는 HTTP 애플리케이션 간에 주고받은 데이터의 블록들이다
- 클라이언트, 서버, 프록시 사이를 흐른다
- 인바운드, 아웃바운드, 업스트림, 다운스트림은 메시지의 방향을 표현한다.
- 인바운드: 원서버 방향으로 향하는 메시지 (서버 방향)
- 아웃바운드: 메시지가 사용자로 돌아오는 메시지 (사용자 에이전트 방향)
- 모든 HTTP 메시지는 다운스트림으로 흐른다.
- 요청과 응답의 벌송자가 업스트림이고, 다운스트림은 목적지이다.
메시지의 각 부분
HTTP 메시지는 데이터의 구조화된 블록. 앞서 살펴본 대로, 시작줄, 헤더, 본문으로 구성된다.
- 시작줄: 이것이 어떤 메시지인지 서술
- 헤더: 속성
- 본문: 데이터. 텍스트나 이진 데이터를 표현할 수 있다. 혹은 아예 생략될 수도 있다.
시작줄과 헤더는 아스키 문자 줄단위로 분리됨. 이 줄바꿈 문자를 CRLF라고 부른다.
메시지 문법
모든 HTTP 메시지는 요청 / 응답 메시지이다. 요청 메시지는 서버에 요청을, 응답은 요청의 결과를 클라이언트로 돌려준다.
요청 메시지의 형식:
<메서드><요청 URL><HTTP 버전> - 시작줄 = 요청줄
<헤더>
<엔터티 본문>
응답 메시지의 형식:
<HTTP 버전><상태 코드><사유 구절> - 시작줄 = 응답줄
<헤더>
<엔터티 본문>
- 요청줄, 응답줄 : 시작줄의 요소들은 띄어쓰기로 구분된다.
- 메서드: 서버에 어떤 동작이 일어나야 하는지 설명해준다.
- 요청 URL: 클라이언트가 서버와 직접 대화하고 있고 경로 구성 요소가 리소스를 가리키는 절대 경로면 문제없다. 서버는 URL에서 생략된 호스트/포트가 자신을 가리키는 것으로 간주한다.
- 버전 : 이 메시지에서 사용 중인 HTTP의 버전이다. HTTP/<메이저>.<마이너> (메이저, 마이너 모두 정수다) 요청과 응답 양쪽 모두에 기술된다. 자신이 따르는 프로토콜의 번호를 상대에 알리기 위한 수단이다. HTTP 버전 1.1 애플리케이션과 대화하는 1.2 애플리케이션은 1.2 버전의 새로운 기능을 사용할 수 없다.
- 상태코드: 요청 중 무엇이 일어났는지 설명하는 세 자리 숫자. 200~299까지 성공을 나타낸다.
- 사유 구절: 상태코드의 의미를 사람이 이해할 수 있게 설명해주는 짧은 문구. 상태 코드 이후부터 줄바꿈 문자열까지 사유 구절이다. 오로지 사람에게만 읽힐 목적으로 작성되어, HTTP 1.1 200 NOT OK나 HTTP 1.1 200 OK나 동등하게 성공 상태 코드를 갖고 있어 성공을 의미하는 것으로 처리한다. HTTP 명세는 사유 구절에 대한 엄격한 규칙을 적용하지 않는다.
헤더
이름, 콜론, 선택적인 공백, 값, CRLF가 순서대로 나타나는 0개 이상의 헤더. 헤더 목록은 빈줄(CRLF)로 끝나 본문과 구분한다. HTTP 1.1같은 특정 버전에서는 특정한 헤더를 포함하여야만 유효한 것으로 간주한다. 요청과 응답 메시지에 추가 정보를 더한다. 기본적으로 이름/값 쌍의 목록이다.
Content-length:19
분류
- 일반 헤더: 요청과 응답 양쪽에 모두 나타낼 수 있다.
- 요청 헤더: 요청에 대한 부가 정보
- 응답 헤더: 응답에 대한 부가 정보
- Entity 헤더: 본문 크기, 콘텐츠 혹은 리소스 그자체를 서술
- 확장 헤더: 명세에 정의되지 않은 새로운 해더
각 Http 헤더는 간단한 문법을 지닌다. 이름, 쉼표, 공백(없어도 됨), 필드 값, CRLF가 순서대로 나온다. 긴 헤더는 여러 줄로 쪼개서 보낼 수 있다.
엔터티 본문:
임의의 데이터 블록을 포함한다. 모든 메시지가 엔터티 본문을 갖는 것이 아니어서 빈줄(CRLF)로 끝날 때도 자주 있다. 헤더나 본문이 없더라도, HTTP 헤더의 집합은 항상 CRLF로 끝난다. HTTP의 화물이라고 할 수 있다. 이미지, 비디오, HTML 문서, 소프트웨어 애플리케이션, 메일 등 다양한 데이터를 실어 나를 수 있다.
이어서 요청 메시지의 메서드, 응답 메시지의 상태코드, 헤더에 대해서 자세히 알아보자.
메서드
서버는 모든 메서드에 구현하지 않을 수 있다. 메서드는 대부분 제한적으로 사용된다. DELETE, PUT 요청은 아무나 저장된 리소스를 삭제하거나 수정하지 못하게 제한 할 수 있다. 이러한 제한은 일반적으로 서버 설정에 의해 정해지며, 사이트마다 서버마다 다를 수 있다.
안전한 메서드 = 서버에 '작용’이 일어나지 않는 요청 메서드
HTTP는 안전한 메서드라 불리는 메서드의 집합을 정의한다. GET, HEAD 메서드는 HTTP 요청의 결과로 서버에 아무 작용도 없음을 의미한다. 작용이 없다는 뜻은 HTTP 요청의 결과로 서버에 일어나는 일은 아무것도 없다는 일이다. 즉 서버 상의 데이터에 변화가 없다는 말과 같다. 예를 들어 POST 메서드로 데이터를 저장하는 요청을 보낸다면, 서버에는 이에 해당하는 작용이 일어날 것이다. 안전한 메서드가 서버에 작용을 유발하지 않는 보장은 없다. 안전한 메서드의 목적은, 서버에 어떤 영향을 줄 수 있는 안전하지 않은 메서드가 사용될 때 사용자들에게 그 사실을 아려주는 애플리케이션을 만들 수 있도록 하는 것이다.
GET
- 서버에 리소스를 달라고 요청할 때 사용
- get 요청 body에 무언가를 담아 요청을 보낼 수는 있지만, 표준 HTTP 설계에선 벗어난 사용법이다.
- 특정한 데이터를 얻기 위해 앞장에서 살펴본 쿼리(질의)를 사용하는 것이 일반적이다.
- get 요청을 통해 얻은 내용은 캐시를 할 수 있다. 같은 요청에 대한 서버의 응답을 저장하고 사용할 수 있다.
- HEAD
- 정확히 GET처럼 행동하지만, 서버는 응답으로 헤더만을 돌려준다. 엔터티 본문(body)는 반환되지 않는다.
- 이를 통해 리소스를 가져오지 않고 그에 대한 메타데이터(컨텐트 타입, 크기 등)를 얻을 수 있다.
- 응답 사태 코드를 통해 개체가 존재하는지 확인할 수 있다.
- 헤더를 통해 리소스가 변경 여부를 확인할 수 있다.
PUT
- 서버에 리소스를 생성하거나 업데이트할 때 사용
- PUT 요청은 지정된 URI에 리소스를 생성하거나, 이미 존재하는 리소스를 대체하기 위해 사용된다.
- 요청의 본문에 데이터를 담아 전송하며, 서버는 이 데이터를 사용해 지정된 URI의 리소스를 생성하거나 업데이트한다.
- POST와 차이점: PUT 요청은 멱등idempotent하다. 즉, 같은 데이터로 같은 요청을 여러 번 수행해도 최종 서버 상태에 동일한 영향을 미친다.
- 그렇게 때문에 주로 이미 존재하는 리소스를 대체할 때 사용한다.
POST
- 서버에 리소스를 생성하라는 요청을 할 때 사용
- POST 요청은 서버에 데이터를 제출하여 새 리소스를 생성하거나, 기존 리소스에 대한 처리를 요청할 때 사용된다.
- 요청의 본문에 데이터를 담아 전송하며, 서버는 이 데이터를 기반으로 새로운 리소스를 생성하거나, 요청에 따른 특정 작업을 수행한다.
- 폼 데이터 제출, 메시지 전송, 파일 업로드 등 서버에 데이터를 제출하여 처리를 요청할 때 사용된다.
- POST 요청은 non-idempotent하다. 같은 요청을 여러 번 수행할 경우, 요청의 효과는 요청마다 달라질 수 있다.
- 같은 POST 요청을 여러 번 수행하면 서버에 여러 개의 리소스가 생성될 수 있으며, 각 요청이 서버 상태에 다르게 영향을 미칠 수 있다.
TRACE
- 서버에 대한 진단을 위해 사용되는 메서드
- 엔티티 본문을 전혀 사용하지 않는다.
- TRACE 메서드는 클라이언트에게 자신의 요청이 서버에 도달했을 때 어떻게 보이는지 알려줌.
- 목적지 서버에서 ‘루프백’ 진단을 시작한다.
- TRACE 요청은 서버로 전송된 요청 메시지를 그대로 받은 후, 응답 본문에 이 메시지를 포함하여 클라이언트에게 돌려보낸다. 이를 통해 클라이언트는 중간에 있는 프록시 서버들이 요청을 어떻게 수정하거나 추가하는지 확인할 수 있다.
- 주로 네트워크 진단, 디버깅, HTTP 통신이 중간 서버에 의해 변경되는 방식을 추적하는 데 사용된다. 예를 들면 요청이 의도한 요청/응답 연쇄를 거쳐가는지 검사할 수 있다.
- 하지만 보통 요청의 메서드에 따라 HTTP 애플리케이션은 다르게 동작한다. 예를 들어 POST는 바로 서버로 요청을 보내는 반면, GET은 웹 케시와 같은 HTTP 애플리케이션으로 전송한다. TRACE는 메서드를 구별하는 메커니즘이 없기에 TRACE 요청을 어떻게 처리할지는 중간 애플리케이션에서 결정해야한다.
클라이언트 -> proxy -> 서버
요청 메시지
TRACE /sample/...
Accept: *
-> 프록시 통과
TRACE /sample/...
Accept: *
Via: 1.1 proxy
-> 서버 도착
-> 서버 응답 메시지에 Via필드가 추가되어 클라이언트에 도착한다.
OPTIONS
- OPTIONS 메서드는 웹 서버에 메서드 지원 범위를 물어본다.
- 특정 리소스에 대해 어떤 메서드를 지원하는 지 물어볼 수 있다.
- 응답은 Allow 헤더를 포함하고 있으며, 이는 해당 리소스에 대해 사용할 수 있는 HTTP 메서드들을 나열한다.
- OPTIONS 요청은 서버의 구성과 지원 기능을 파악하는 데 유용하며, 리소스를 변경하지 않는 안전한 메서드로 분류된다.
DELETE
- 서버에 지정된 리소스를 삭제하도록 요청
- DELETE 요청의 처리는 서버의 구현에 따라 다르다.
- HTTP 명세는 서버가 클라이언트에 알리지 않고 요청을 무시하는 것을 허락하기 때문이다.
확장 메서드
확장 메서드는 HTTP/1.1 명세에 정의되지 않은 메서드다. WebDAV HTTP 확장 메서드의 몇가지 예시이다.
- LOCK: 사용자가 리소스를 잠글 수 있게 해준다. 예를 들어 사용자가 편집 중일 때 다른 사람이 같은 문서를 편집할 수 없게 해준다.
- MKCOL: 사용자가 문서를 생성할 수 있게 해준다.
- COPY: 서버에 있는 리소스를 복사한다.
- MOVE: 서버에 있는 리소스를 옮긴다.
모든 확장 메서드가 형식을 갖춘 명세로 정의되지 않는다. 누군가 임의로 정의한 메서드는 대부분의 HTTP 애플리케이션이 이해할 수 없을 것이고, 반대로 내 HTTP 애플리케이션이 이해할 수 없는 확장 메서드를 사용하는 애플리케이션과 마주칠 수도 있다.
상태 코드
상태 코드는 클라이언트에게 각 트랜잭션을 이해할 수 있는 쉬운 방법을 제공한다.
상태코드는 번호대에 따라 크게 다섯가지로 나뉜다.
100-199: 정보성 상태코드
HTTP/1.1에서 도입되었다. 비교적 새로운 코드들이다.
- 100 Continue: 요청의 시작 부분 일부가 받아들여졌으며, 클라이언트는 나머지를 이어서 보내야 함을 의미. 이를 보낸 후 서버는 반드시 요청을 받아 응답해야한다.
- 101 Switching Protocols: 클라이언트가 Upgrage 헤더에 나열한 것 중 하나로 서버가 프로토콜을 바꾸었음을 의미
- 100 Continue와 클라이언트: 클라이언트에서 엔터티를 서버에 보내기 전에 100 응답을 기다린다면, Expect:100-contunue로 시작하는 요청 헤더를 보내야한다. 기다리지 않는 다면, 이 헤더를 보내지 않는다. 서버의 응답을 다시 기다리더라도, 약간의 타임아웃 이후 보내야한다.
- 100 Continue와 서버: Expect:100-continue 요청 헤더를 받는다면, 에러코드 혹은 100 Continue 응답 둘 중 하나를 보내야한다. 만일 응답을 보내기 전에 클라이언트에서 엔터티의 일부(전체)를 받았다면 최종 응답을 보내야한다
- .조건부 요청 헤더의 Expect 참조*
200-299: 성공 상태코드
성공한 요청에 대응하는 의미있는 상태 코드 배열이다. 각각 다른 종류의 요청에 대응한다.
- 200 Ok: 요청은 정상이고 응답 body(엔터티 본문)에 요청한 리소스를 포함한다.
- 201 Created: 서버 개체를 생성하는 요청의 성공 코드. 생성된 리소스에 대한 구체적인 참조가 담긴 Location 헤더와 그 리소스를 참조할 수 있는 여러 URL을 본문에 포함해야 한다. 서버는 201 상태 코드를 보내기 전에 반드시 객체를 생성해야 한다.
- 202 Accepted: 요청은 받아들여졌으나 서버는 아직 그에 대한 어떤 동작도 수행하지 않았다. 서버가 요청의 처리를 완료할 것인지에 대한 어떤 보장도 없다.요청이 받아들이기에 적법해 보인다는 의미 뿐이다. 서버는 응답 엔터티 본문에 요청에 대한 상태, 요청 처리가 언제 완료될 것인지 추정도 포함하는 것이 좋다.
- 203 Non-Authoritative Information: 엔터티 헤더에 들어있는 정보가 원래 서버가 아닌 리소스의 사본에서 왔다. 중개자(프록시)가 리소스 사본을 갖고 있지만 메타데이터를 검증하지 못한 경우 발생한다. 반드시 사용되어야할 코드는 아니다.
- 204 No Content: 응답 메시지는 헤더, 상태줄을 포함하지만 body는 포함하지 않는다. 주로 브라우저를 새 문서로 이동시키지 않고 갱신하고자 할 때 사용했다.
- 205 Reset Content: 주로 브라우저를 위해 사용되는 코드. 브라우저에게 현재 페이지에 있는 HTML 폼에 채워진 모든 값을 비우라고 한다. (요즘은 잘 안쓰일듯)
- 206 Partial Content: 부분 혹은 범위 요청이 성공. Range 헤더 참조. 206 응답은 Content-Range와 Date 헤더를 반드시 포함. Etag, Content-Location 중 하나는 반드시 포함해야한다.
300-399: 리다이렉션 상태코드
클라이언트가 관심있어 하는 다른 리소스의 위치를 사용하라고 말해주거나, 그 리소스의 내용 대신 다른 대안 응답을 제공한다. 만약 리소스가 옮겨졌다면 옮겨진 리소스가 옮겨졌으며, 어디서 찾을 수 있는 지에 대한 정보를 줄 수 있다. 이는 브라우저가 자동으로 새 위치로 이동할 수 있게 해준다.
300번대의 몇몇 코드는 리소스의 로컬 복사본이 원서버와 비교해 유효한지 확인할 때 사용한다. 이를 통해 복사본이 여전히 최신인지 혹은 수정이 이루어졌는지 검사할 수 있다.
- 300 Multiple Choices: 요청된 리소스가 여러 형태로 존재하며, 클라이언트가 선호하는 형태를 선택해야 하는 경우
- 301 Moved Permanently: 요청된 리소스가 새로운 URI로 영구적으로 이동됐을 때. 클라이언트는 미래의 요청에서 새 URI를 사용.
- 302 Found: 요청된 리소스가 일시적으로 다른 URI에 위치. 이 상태 코드는 리소스의 임시 이동을 나타냄.
- 303 See Other: 요청에 대한 응답을 다른 URI에서 찾을 수 있으며, GET 메서드를 사용하여 리소스를 검색해야함
- 304 Not Modified: 클라이언트가 조건부 GET 요청을 했고, 리소스가 마지막 요청 이후 변경되지 않았다면, 서버는 이 상태 코드를 사용하여 응답합니다. 이는 리소스의 로컬 복사본을 사용할 수 있음을 나타냄.
- 307 Temporary Redirect: 요청된 리소스가 일시적으로 다른 URI에 위치해 있으며, 클라이언트는 미래의 요청에 대해 원래의 URI를 계속 사용해야함
- 308 Permanent Redirect: 요청된 리소스가 새로운 URI로 영구적으로 이동되었으며, 클라이언트는 미래의 모든 요청에서 새 URI를 사용해야함
400-499: 클라이언트 에러 상태코드
클라이언트가 서버에서 다룰 수 없는 요청을 보내는 경우. 잘못 구성된 요청 메시지, 존재하지 않는 URL이나 접근 권한이 없는 요청 등이 있다. 많은 클라이언트는 브라우저에 의해 처리되나 404를 비롯한 몇몇은 서버로 전달된다.
- 400 Bad Request: 일반적으로 잘못된 요청을 보냈음을 알린다.
- 401 Unauthorized: 리소스를 얻기 전에 클라이언트에 인증을 하라고 요구하는 응답. 클라이언트는 요청에 인증 정보를 포함해야 한다.
- 403 Forbidden: 서버가 요청을 이해했지만, 서버에 의해 거부할 때 사용. 보통 서버가 거절의 이유를 숨기고 싶을 때 사용한다.
- 404 Not Found: 서버가 요청한 리소스를 찾을 수 없을 때.
- 405 Method Not Allowed: URL에 대해 지원하지 않는 메서드로 요청했을 때 사용. 어떤 메서드가 가능한지 알려주기 위해 응답 헤더에 Allow를 ...