HTTP message
1. 인바운드 - 아웃바운드, 다운스트림
서버를 기준으로 유입되는 트래픽 / 요청등을 인바운드, 그에 대한 응답이나 직접 클라이언트에게 응답을 보내는 경우를 아웃바운드라고 한다. 즉, 서버를 기준으로 들어오는 것은 인바운드, 나가는 것은 아웃바운드라고 생각하면 된다.
HTTP 메시지는 항상 물처럼 흐르고 역류 하지 않는다. 메시지의 발신자는 수신자의 업스트림이 되며, 메시지는 다운스트림으로 보내진다. 서버인지 클라이언트인지에 상관없이 업스트림과 다운스트림은 상황에 따라 바뀌게 된다.
client(업스트림) -> server(다운스트림)
client(다운스트림) <- server(업스트림)
2. Message
1. 메시지의 세 부분
- 메시지는 보통 [시작줄 - 헤더 - 본문]의 구조로 되어있다.
2. 메시지의 구조
- Reqeust의 경우
<Method> <URL> <HTTP version> ] 시작줄
<Header> ] 헤더
<Content> ] 본문
- Response의 경우
<HTTP version> <Status code> <Reason phase> ] 시작줄
<Header> ] 헤더
<Content> ] 본문
- Method: 사용된 HTTP method의 종류.
- URL: Request를 요청받는 측의 URL.
- HTTP version: HTTP 버전을 나타내며, 어떤 어플리케이션이 지원하는 가능 높은 HTTP 버전을 나타낸다.
- Status code: 어떤 request의 실행결과를 숫자로 보여준다.
- Reason phase: 사람이 알아볼 수 있게, status code와 함께 리턴되는 간단한 메시지.
- 본문: 있을수도 있고, 없을수도 있는
화물. HTTP가 이것을 운송하도록 설계되었다. 이미지, 비디오, 텍스트, 소프트웨어 어플리케이션 등 많은 것을 포함할 수 있다.
기억해야 할 점은 request, response 메시지의 본문은 있을수도 있고 없을수도 있다는 것이며, 메시지 본문의 유무와 상관없이 Header의 끝은 반드시 CRLF로 마무리 되어야 한다는 것이다.
3. Header
1. Header의 특징
- 0개 혹은 그 이상의 헤더가 위치할 수 있다.
- 각각 CRLF로 구분한다.
- key-value의 구조를 가진다.
Content-Type: text/html
2. Header의 종류
A. 일반 헤더
- 일반 헤더는 클라이언트와 서버 양쪽 모두가 사용한다. 일반적으로, 메시지에 대한 아주 기본적인 정보를 제공하는 경우 사용하게 된다.
| 헤더 | 설명 |
|---|---|
| Connection | 클라이언트-서버가 요청/응답 연결에 대한 옵션. MDN |
| Date | 메시지가 만들어진 날짜와 시간. |
| MIME-Version | 발송자가 사용한 MIME의 version. |
| Trailer chunked transfer | 청크와 지속 커넥션을 위한 헤더(나중에 자세히 기술 예정). |
| Trasfer-Encoding | 메시지에 적용된 인코딩의 종류. |
| Upgrade | 발송자가 업그레이드하길 원하는 새 버전이나 프로토콜. |
| Via | 메시지가 거쳐온 중개자(proxy, gateway). |
B. 일반 캐시 헤더
| 헤더 | 설명 |
|---|---|
| Cache-Control | 캐시 지시자를 전달. MDN |
| Pragma | deprecated. |
C. 요청 헤더(Request Header)
- 요청(Request) 메시지에서만 의미를 갖는 헤더로, 보통 클라이언트 측에서 자동으로 작성되어 보내지는 경우가 많다. 물론, 조작될 가능성도 있으니 주의해야 한다.
예시
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36
| 헤더 | 설명 |
|---|---|
| Client-IP | 클라이언트의 IP. |
| From | 클라이언트 사용자의 메일 주소. |
| Host | 요청의 대상이 되는 서버의 호스트명과 포트. |
| Referer | 현재의 요청 URI가 들어있던 문서의 URL. 즉 현재 페이지 이전의 페이지 주소. |
| User-Agent | 요청을 보낸 어플리케이션의 이름. |
- Accept 관련 헤더는 주로 클라이언트에서 사용되는 미디어의 종류에 대해서 보내게 된다. 각 헤더는 콤마로 구분 가능하며, 와일드카드 역시 동작한다.
예시
Accept: text/html
Accept: image/*
Accept: text/html, application/xhtml+xml
| 헤더 | 설명 |
|---|---|
| Accept | 서버가 클라이언트에 보내도 상관없는 미디어의 종류. MDN |
| Accept-Charset | 서버가 클라이언트에 보내도 상관없는 문자셋의 종류. |
| Accept-Encoding | 서버가 클라이언트에 보내도 상관없는 인코딩 타입. |
| Accept-Language | 서버가 클라이언트에 보내도 상관없는 언어. |
- 조건부 요청 헤더는 클라이언트가 요청에 대해 몇몇 제약을 넣고자 할 때 사용한다. 예를들어 클라이언트가 이미 어떤 문서의 사본을 가지고 있는 상태라면, 클라이언트는 서버에게 이 문서의 사본과 원본이 다를때만 전송해 달라고 요청 할 수 있다.
| 헤더 | 설명 |
|---|---|
| If-Match | 문서의 엔터티 태그가 일치하는 경우에만 문서를 가져온다. |
| If-Modified-since | 주어진 날짜 이후 리소스가 변경되지 않았다면 요청을 제한. |
| If-None-Match | 문서의 엔터티 태그가 일치하지 않는 경우에만 문서를 가져온다. ETag와 함께 쓰이기도 한다. |
| If-Range | 문서의 특정 범위에 대한 요청 |
| If-Unmodified-Since | 주어진 날짜 이후 리소스가 변경되었다면 요청을 제한. |
| Range | 서버가 range-request를 지원하는 경우 리소스에 대한 특정 범위를 요청(나중에 자세히 기술 예정). |
- 보안 헤더는 간단한 인증요구/응답을 위해 사용된다. 보안 헤더의 종류는 아니지만, Cookie역시 이러한 역할을 한다고 볼 수 있다.
| 헤더 | 설명 |
|---|---|
| Authorization | 클라이언트가 서버에 제공하는 인증 그 자체에 대한 정보. |
- proxy 요청 헤더
| 헤더 | 설명 |
|---|---|
| Max-Forward | Proxy될 수 있는 최대 회수. TRACE method와 함께 쓰인다. |
| Proxy-Authorization | Authorization과 같으나, proxy인증 시 쓰인다. |
| Proxy-Connection | Connection과 같으나, proxy인증 시 쓰인다. |
D. 응답 헤더(Response Header)
- 응답(Response) 헤더는 클라이언트에게 부가 정보를 제공한다.
| 헤더 | 설명 |
|---|---|
| Age | 응답이 경과된 시간. |
| Public | 서버가 특정 리소스에 대해 지원하는 요청 method의 목록. |
| Retry-After | 현재 리소스가 사용불가능한 상태일때, 사용 가능해지는 시각. |
| Server | 서버의 어플리케이션 이름과 버전. |
| Warning | Reason phase 보다 더 자세한 경고 메시지. |
- 협상 헤더
| 헤더 | 설명 |
|---|---|
| Accept-Ranges | 서버가 자원에 대해 받아들일 수 있는 범위의 형태. |
| Vary | 서버가 확인해 보아야 하고 응답에 영향을 줄 수 있는 헤더들의 목록. |
- 응답 보안 헤더
| 헤더 | 설명 |
|---|---|
| Proxy-Authenticate | Proxy에서 클라이언트로 보낸 인증요구의 목록. |
| Set-Cookie | 서버에서 사용자 브라우저에 쿠키를 전송하기 위해 사용. 이 헤더를 받았을 경우 브라우저는 Cookie를 저장하고, 다음번 요청의 Cookie에 해당 내용을 포함한다. MDN |
| WWW-Authenticate | 서버에서 클라이언트로 보낸 인증요구의 목록. |
E. 엔터티 헤더
-
HTTP message의 엔터티(본문)에 대해 설명하는 헤더들로, 요청과 응답 양쪽 모두에서 사용할 수 있다.
-
정보 헤더
| 헤더 | 설명 |
|---|---|
| Allow | 이 엔터티에 대해 수행될 수 있는 요청 method들을 나열. |
| Location | 엔터티가 실제로 위치하고 있는 곳. 리소스에 대한 실제 URL을 알려줄 때 사용. |
- 콘텐츠 헤더
| 헤더 | 설명 |
|---|---|
| Content-Base | Base URL. |
| Content-Encoding | 엔터티에 적용된 인코딩. |
| Content-Language | 본문을 이해하는데 가장 적절한 언어. |
| Content-Length | 본문의 길이나 크기. |
| Content-Location | 리소스의 실제 위치. |
| Content-MD5 | 본문의 MD5 checksum. |
| Content-Range | 전체 리소스에서 엔터티가 해당하는 범위를 바이트 단위로 표현. |
| Content-type | 본문의 객체 타입. |
- 엔터티 캐싱 헤더
| 헤더 | 설명 |
|---|---|
| ETag | 엔터티에 해당하는 엔터티 태그. 참고 링크에 따르면, 엔터티를 식별할 수 있는 hash value가 필요함. 참고 |
| Expires | 원본을 다시 받아와야하는 일시. |
| Last-Modified | 가장 최근에 엔터티가 변경된 일시. |
4. Method
Method는 클라이언트가 서버측에 특정한 동작을 요청하는데 쓰이는 것으로, 서버마다 구현되어있는 method는 각각 다를 수 있지만, 개발자는 최대한 method의 목적에 맞는 기능을 구현해야 한다.
A. 안전한 method
HTTP에는 안전한 method의 집합이 있다. 안전한 method란 다음과 같은 method를 의미한다.
- HTTP 요청으로 인해 서버 혹은 DB에 아무런
작용이 일어나지 않는 method. 작용이란 DB에 새로운 값이 입력, 수정, 삭제되거나 신용카드로 대금이 청구되는 등의 동작을 이야기 한다.- 안전한 method에는 GET, HEAD등이 있다.
B. Method의 종류
| method | 기능 |
|---|---|
| GET | 단순한 자원의 요청. |
| HEAD | GET과 비슷하지만, header만 반환. |
| PUT | 요청한 URL과 본문으로 서버는 새로운 문서를 만들거나, 기존 URL에 해당하는 문서를 변경. |
| POST | 서버에 데이터를 보내기위해 사용. |
| OPTIONS | 서버가 지원하는 method를 반환. |
| DELETE | 자원을 삭제 |
| TRACE | 주로 진단시에 사용. 클라이언트에게 자신의 요청이 서버에 도달했을 때 어떻게 보이기 되는지 알려줌. |
| PATCH | PUT과 유사하나, 문서 전체를 바꾸지 않고 일부만 바꿀때 사용. |
-
HEAD method를 사용하게 되면, 리소스를 직접 가져오지 않고 리소스의 존재 여부, 타입 등을 알아낼 수 있다. HTTP/1.1 스펙을 준수하기 위해서는 HEAD가 반드시 구현되어 있어야 하고, HEAD를 통해 반환되는 header와 GET을 통해 반환되는 header는 반드시 일치해야 한다.
-
PUT과 POST method가 하는 일은 조금 다른데, 실제로 api서버를 개발할 때 POST는
새로 생성PUT은변경 혹은 수정에 사용했었던 기억이 있다. -
PATCH라는 method는 책에 소개되어있지는 않지만 예전에 api서버를 개발할 때의 기억이 있어 추가해 보았다. PATCH는 PUT과 비슷한 역할을 하지만, PUT은 문서 전체를 변경하는 대신 PATCH는 일부분만 변경하기 때문에 update기능을 구현하는데에 의미적으로 조금 더 적합하지 않나 하는 생각이 든다.
5. Status code, Reason phase
Status code와 reason phase는 response message에 포함되어 반환되는 값으로, 클라이언트의 요청에 대해 서버가 처리한 결과이다. Status code는 보통 세자리의 숫자기 때문에 코드상에서 에러 처리등의 용도로 사용한다. Reason phase는 status에 대해서 사람이 좀 더 알아보기 쉬운 짧은 readable text 형태이기 때문에 status code를 좀 더 쉽게 이해하도록 도와준다.
Status code는 상태에 따라 반환하는 code와 범위를 미리 지정해 놓았다 (RFC 7231).
| 범위 | Predefined range | 분류 |
|---|---|---|
| 100-199 | 100-101 | 정보 |
| 200-299 | 200-206 | 성공 |
| 300-399 | 300-305 | Redirection |
| 400-499 | 400-415 | Client error |
| 500-599 | 500-505 | Server error |
미리 정의된 code를 제외하고 status code를 새로 기술할 때는 두 가지 규칙을 따라야 한다.
- 상태코드의 약속된 범위내에 포함되는 에러라고 간주할 수 있어야 한다. 즉 성공을 나타내는 200번대 status code에 서버 에러에 대한 code를 정의하면 안된다.
- 미리 정의된 status code를 임의로 변경하지 않는다.
A. 200번대 status code
200번대의 status code는 요청에 대해 성공했음을 알려주는 code로 구성되어 있다.
| 코드 | Reason phase | 의미 |
|---|---|---|
| 200 | OK | 요청은 정상이고, 엔터티 본문은 요청된 리소스를 포함하고 있음. |
| 201 | Created | 개체를 생성하는데 성공함. 서버는 응답 메시지에 생성된 리소스의 URL을 Location헤더와 엔터티 본문에 포함해야 함. |
| 202 | Accepted | 요청은 받아들여졌으나 서버는 아직 동작을 수행하지 않음. 서버는 응답 메시지에 요청에 대한 상태와 처리 완료 시점에 대해 엔터티본문에 기술해 주면 좋음. |
| 203 | Non-Authoitative Information | 엔터티 헤더에 들어있는 정보가 원래 서버가 아닌 리소스의 사본에서 왔음. |
| 204 | No Content | 응답 메시지에 엔터티 본문을 포함하고 있지 않음. |
| 205 | Reset Content | 브라우저에게 현재 form에 채워진 모든 값을 비우라고 지시. |
| 206 | Partial Content | 부분 혹은 범위 요청 성공. 서버는 응답 메시지에 Content-Range와 Date를 반드시 포함해야 하며, ETag와 Content-Location중 하나의 헤더도 반드시 포함해야 함. |
B. 300번대 status code
300번대의 status code는 요청에 대한 리소스가 옮겨지거나 다른 위치를 참조해야할 때 사용되며, 이는 브라우자가 사용자를 귀찮게 하지 않고 알아서 새 위치로 이동할 수 있게 해준다.
| 코드 | Reason phase | 의미 |
|---|---|---|
| 300 | Multiple Choice | 클라이언트가 동시에 여러 리소스를 가리키는 URL을 요청한 경우, 리소스의 목록과 함께 반환됨. 예를들면, 어떤 서버가 하나의 HTML문서를 한국어와 영어로 제공하는 경우 등에 사용 가능. 서버는 Location 헤더에 선호하는 URL을 포함할 수 있음. |
| 301 | Moved Permanently | 클라이언트가 요청한 리소스가 응답 메시지의 Location 헤더에 주어진 URL에 일시적으로 이동되었음. 브라우저는 응답 메시지의 Location 헤더에 주어진 URL로 이동하고 검색엔진은 링크를 갱신함. |
| 302 | Found | 301과 동일함. 브라우저는 응답 메시지의 Location 헤더에 주어진 URL로 이동하지만, 검색엔진은 링크를 갱신하지 않음. |
| 303 | See Other | 새로운 리소스로 연결되는 것이 아닌, 확인 페이지 또는 업로드 진행 페이지등과 같은 곳으로 연결됨. 일반적으로 PUT, POST 요청에 대한 응답으로 클라이언트에게 리소스의 위치를 알려줌. |
| 304 | Not Modified | 주로 캐시를 목적으로 사용됨. If-None-Match 또는 If-Modified-Since 같은 조건부 헤더를 사용하였을때, 최근에 문서가 수정된 적이 없을 경우 이 code가 반환되며 클라이언트는 계속해서 기존에 캐시된 버전을 사용할 수 있음. 해당 code의 응답 메시지는 엔터티 본문을 가져서는 안됨. |
| 305 | Use Proxy | 리소스가 반드시 proxy를 통해 접근되어야 함. Proxy의 위치는 Location 헤더를 통해 주어짐. 현재 proxy의 in-band 설정에 대한 보안상의 걱정으로 인하여 권장하지 않음. |
| 306 | 현재 사용되지 않음 | |
| 307 | Temporary Redirect | 301과 동일함. 원래 요청의 메서드와 본문은 리디렉션 된 요청을 수행하기 위해 다시 사용됨. 302를 사용할 경우, 예전의 클라이언트들은 GET 방식을 잘못 변경했지만 307은 method와 엔터티 본문이 변하지 않는 것을 보장함. |
C. 400번대 status code
400번대의 status code는 클라이언트의 에러를 나타내며, 404와 같은 몇몇 에러를 제외하면 브라우저에 의해 처리된다. 400번대의 status code는 종류가 많기때문에, 주로 사용되는 것에 대해서만 설명하고자 한다. 나머지 status code에 대해서는 이곳을 참고하면 좋을 것 같다.
| 코드 | Reason phase | 의미 |
|---|---|---|
| 400 | Bad Request | 클라이언트의 요청을 서버가 이해할 수 없음. |
| 401 | Unauthorized | 클라이언트가 스스로를 인증해야 함. |
| 403 | Forbidden | 클라이언트의 접근 권한이 없음. 401과 다른점은 서버가 클라이언트가 누구인지 알고있음. |
| 404 | Not Found | 요청한 URL을 찾을 수 없음. |
| 405 | Method Not Allowed | 현재 요청한 method를 사용할 수 없음. GET과 HEAD는 제거될 수 없으며 따라서 이 code를 반환할 수 없음. |
| 408 | Request Timeout | 클라이언트의 요청을 완수하기에 시간이 오래 걸리는 경우. |
D. 500번대 status code
500번대의 status code는 서버의 에러를 나타낸다.
| 코드 | Reason phase | 의미 |
|---|---|---|
| 500 | Internal Server Error | 서버가 요청을 처리할 수 없게 만드는 에러에 봉착함. |
| 502 | Bad Gateway | Proxy나 gateway 역할을 하는 서버가 요청을 처리하는 데 필요한 응답을 얻기 위해 작업하는 동안 잘못된 응답을 수신했음 (상위 gateway 접속 불가 등). |
| 503 | Service Unavailable | 서버가 요청을 처리할 준비가 되지 않음. 유지보수 혹은 과부하가 원인. 서버는 응답 메시지에 Retry-After헤더를 사용하는 것이 좋다. |
| 504 | Gateway Timeout | 408과 비슷하지만, 다른 서버에 요청을 보내고 응답을 기다리다 timeout이 발생한 상황. |
| 505 | HTTP Version Not Supported | 서버가 지원할 수 없거나 지원하지 않는 버전의 프로토콜로 된 요청을 받음. |
6. Conclusion
HTTP 완벽 가이드의 3장을 가볍게 정리해 보았다. 저번과 마찬가지로 대충 알고 있던 부분을 채울수 있어서 좋았고, 몰랐던 부분을 알수 있게되어 더 느낌이 좋았다. 다만 이번의 글은 “공부했다!”라는 느낌 보다는 단순한 정보의 나열처럼 보이는 것이 조금은 아쉽다.
특히 header부분을 공부하고 나서보니 개발자 도구의 network탭이 새롭게 보이는 효과를 보았다. 생각보다 header가 큰 역할을 하고 있으며, 적절히 사용하면 앞으로의 프로젝트에도 도움이 될 것이라 생각한다.