I. HTTP: 웹의 기초
03 HTTP 메시지
HTTP의 메시지는 HTTP 애플리케이션 간에 주고 받는 데이터의 블록들이다. 메세지는 클라이언트, 서버, 프록시를 흐른다. 이 메세지의 흐름의 방향을 표현하기 위한 용어로 "인바운드", "아웃바운드", "업스트림", "다운스트림"이 존재한다. 여기서 인바운드와 아웃바운드는 AWS를 사용하면서 경험했을 것이다. 지금까지 인바운드는 들어오는 것, 아웃바운드는 나가는 것으로 이해했다면 본래 이 용어들의 의미로 이해해보자.
- 인바운드, 아웃바운드
인바운드와 아웃바운드는 트랜잭션의 방향을 표현하기 위해 사용된다. 서버쪽으로 이동하는 것은 인바운드, 클라이언트쪽으로 이동하는 것을 아웃바운드라고 부른다. AWS에서는 서버 쪽으로 들어오는 것을 인바운드, 나가는 것을 아웃바운드로 표현한 것은 AWS가 서비스를 제공하는 서버의 입장이기 때문이다.
- 업스트림, 다운스트림
HTTP 메세지는 강물과 같아서 위에서 아래로 흐른다. 발송자는 위, 받는 사람은 아래에 있다. 따라서 모든 메세지는 요청(req)이냐 응답(res)이냐에 관계없이 다운스트림, 즉, 아래로 흐른다.
이제, HTTP 메세지가 어떤 모습을 하고 있는지 확인해보자. 메세지는 req, res의 두 종류가 있으며 시작점, 헤더, 본문(body)로 구성되어 있다.
각 메세지는 대체로 다음의 구조를 가집니다. 시작줄만 다르고 헤더와 바디는 같습니다. 특기할 점이라면 헤더와 바디는 CRLF(빈 줄)로 구별되어 있으며 바디에 데이터가 없다고 하더라도 빈 줄이 있어야 한다는 것입니다.
- 메서드
요청 메세지는 메서드로 시작합니다. 서버에게 무엇을 해야 하는지 알려줍니다. 여기서 GET, HEAD는 '안전한 메서드'라고 합니다. HTTP 요청을 날려도 서버에는 어떤 변화가 없기 때문입니다.
- GET : 홈페이지를 보여달라는 것입니다. 일반적인 이동에 해당합니다.
- HEAD : GET과 같습니다. 유일한 다른 점은, 헤더만을 받는 것으로 본문은 받지 않는다는 것입니다. 리소스를 가져오지 않고도 HEAD를 조사할 수 있습니다.
- PUT : 서버에 문서를 씁니다. 사용자의 요청에 따라 파일을 추가할 수 있기 때문에 대개 로그인을 요구합니다. 아무나 서버에 리소스를 넣게 할 수는 없으니까요.
- POST : 주로 form을 지원하기 위해 주로 사용합니다. 로그인, 로그아웃, 회원가입을 구현하기 위해 form의 method를 POST로 설정하는 게 주된 사용 목적입니다. input에 입력한 정보는 지정한 name에 담겨 요청 메세지의 본문에 전달됩니다.
- TRACE : 사용자는 자신의 요청이 어떤 경로를 거쳐 서버로 전달되는지를 TRACE로 확인할 수 있습니다. TRACE 메서드는 주로 진단을 위해 사용됩니다. TRACE 요청은 본문이 없습니다.
- OPTIONS : 여러 메서드를 개별적으로 실행하지 않고도 무슨 메서드를 사용 가능한지 체크합니다. 응답 메세지의 헤더에 Allow 항목에 무엇이 가능한지 적혀 있습니다.
- DELETE : 요청한 URL을 삭제 한다. 그러나 반드시 삭제가 되지는 않는데 서버가 클라이언트에게 알리지 않고 요청을 무시할수도 있기 때문이다.
- 확장 메서드
확장 메서드는 HTTP/1.1 명세에 정의되지 않은 메서드다. MOVE, LOCK, MKCOL, COPY등의 확장 메서드가 있고 이것 외에도 개발자들이 마련한 새로운 메서드도 존재하나 HTTP 어플리케이션이 이해하지 못할 수도 있으니 전통적인 메서드를 활용하는 것이 좋다.
- 상태 코드
express framwork의 신버전에서는 상태 코드를 붙여야만 작동하게끔 하려는 움직임이 있으므로 상태 코드를 눈여겨 보자.
어떤 강의에서 재미있게 설명한 게 있어서 가져와보았다.
1XX: 아직 처리중
2XX: 자, 여기있어
- 200: 성공(success), GET, PUT
- 201: 작성됨(created), POST
- 204: 내용 없음 (No Conent), DELETE
4XX: 니가 문제임 (클라이언트 쪽)
- 400: 잘못된 요청 (Bad Request)
- 401: 권한 없음 (Unauthorized)
- 404: 찾을 수 없음 (Not found)
- 409: 충돌 (Conflict)
5XX: 내가 문제임 (서버 쪽)
- 500: 서버 에러 (Interel server error)
-
1xx : 정보성 상태 코드
- 100 Continue : 계속 해도 좋습니다. 서버는 준비가 되었으니 req를 보내십쇼.
100 Continue의 의도는 req 메세지의 본문을 서버가 받아들일 것인지 확인하려할 때 그 확인 작업을 최적화하기 위한 의도로 도입된 것이다. 클라이언트와 서버 양쪽의 관점으로 100 Continue를 보자.
먼저 클라이언트 측에서 본문이 담긴 req을 서버에 보내기 전 100 Continue 응답을 받고 싶다면 Expect 요청 헤더를 보내야 한다. 물론 클라이언트 측에서는 100 Continue 응답을 서버가 보내주기를 언제까지 계속 기다릴 수는 없으므로 시간이 지나면 그냥 본문을 보내는 게 일반적이다.
한편 서버 측에서 Expect 요청 헤더가 포함된 req 메세지를 받는다면 100 Continue 응답이나 에러 코드를 보내야 합니다. Expect 요청 헤더가 없는데도 100 Continue를 보내면 안됩니다. 그러나 종종 잘못 만들어진 서버는 보내기도 합니다. 또, 100 Continue를 보내기 전에 클라이언트 측에서 req를 보냈다면 서버는 굳이 100 Continue를 보낼 필요가 없습니다.
프록시 서버는 100 Continue을 요구하는 req를 받게 된다면 다음 홉 서버(next-hop)가 HTTP/1.1 이상을 지원하거나 어떤 버전의 HTTP를 사용하는지 모른다면 Expect 헤더를 포함시켜 요청을 전달하고, 다음서버가 HTTP/1.1보다 이전의 버전을 사용한다는 것을 알면 보내지 않고 417 Expectation Failed 에러를 응답한다.
-
2xx : 성공 상태 코드
- 200 OK : req는 정상적이고 요청한 값을 잘 처리했다. 문제 없음.
- 201 Created : POST 메서드를 위해 존재하는 상태 코드입니다.
생성된 리소스에 대한 정보를 Location 헤더와 함께 그 리스소를 볼 수 있는 URL을 엔터티 본문에 포함합니다. 서버는 요청한 내용을 생성한 후에 201 Created를 보내야 합니다.
- 202 Accepted : 서버가 req는 받았으나 요청을 처리할 것인지에 대한 보장이 없다.
좋은 서버는 엔터티 본문에 요청에 대한 상태와 요청의 처리가 언제 될 것인지에 대한 추정을 적습니다.
- 203 Non-Authoritative information
- 204 No Content
- 205 Reset Content
- 206 Partial Content
-
3xx : 리다이렉션 상태 코드
리소스가 없거나 잘못 요청되었을 경우 홈으로 리다이렉션되는 경우를 종종 경험해보았을 것이다. 리다이렉션으로 이동한 경우 300번 대 상태코드를 받게 된다.
- 300 Multiple Choices : 여러 리소스를 가리키는 URL을 req 했으니 골라라
- 301 Moved Permanently : 요청한 URL이 옮겨졌다.
- 302 Found : 301과 동일하다.
- 303 See Other : 리소스를 다른 URL에서 가져와야 한다.
- 304 Not Modified
- 305 Use Proxy
- 307 Temporary Redirect
-
4xx : 클라이언트 에러 상태 코드
클라이언트가 서버가 다룰 수 없는 req를 보냈을 때를 클라이언트 측 오류로 qhs다. 가장 흔하게 발생하는 건 존재하지 않는 경로에 대한 요청이다. 404 Not Found가 대표적이다.
- 400 Bad request
- 401 Unauthorized
- 403 Forbidden
export const isLoggedIn = (req, res, next) => {
if (req.isAuthenticated()) {
next();
} else {
res.status(403).send("로그인 필요");
}
};
- 404 Not Found
- 405 Method Not Allowed
...
-
5xx : 서버 에러 상태 코드
4xx 오류와 달리 클라이언트가 올바른 req를 보냈음에도 서버 쪽에서 에러가 난 경우이다. 서버의 제한에 클라이언트가 걸린 걸수도 있고 서버 구성 요소에서 난 오류일 수도 있다. 클라이언트 입장의 프록시는 이 오류를 자주 접하게 된다.
- 500 Internal Server Error
서버가 req를 처리할 수 없는 에러를 만났을 때
- 501 Not Implemented
클라이언트가 서버의 능력을 넘어서는 req를 날렸을 때
- 502 Bad Gateway
- 503 Service Unavailable
지금을 서버가 req를 처리할 수 없으나 나중에는 가능해 질 것
- 504 Gateway Timeout
다른 서버에게 요청을 보냈으나 응답이 너무 늦어져서 타임아웃된 경우
- 505 HTTP Version Not Supported
- 헤더
Zercho 블로그에 정리나 설명이 매우 잘 되어 있으므로 게시물들을 일독하길 권장함.
헤더에도 여러 종류가 존재하며 각 헤더가 보여주는 정보도 다르다. 여기서 유용한 개념은 헤더를 하나의 블록이 아니라 요소로 생각하는 것이다. 개발자 도구에서 Network 탭 - Headers를 통해 헤더를 확인할 수 있다. 개발자 도구는 헤더의 종류별로 구별해준다.
많은 헤더를 다 외우는 것은 불가능하고 해서도 안되는 짓이다. 궁금해지면 찾아보는 식으로 해결하자.
- 일반 헤더 (General)
일반 헤더는 클라이언트, 서버 양 쪽 다 사용한다. 예를 들어 Date 헤더는 메세지가 만들어진 시간을 표시한다.
Connection 클라이언트와 서버가 커넥션에 대한 옵션을 정할수 있게 알려줌
Date 메세지가 생성된 날짜와 시간
MIME-Version 발송자가 사용한 MIME 버전
Trailer chunked transfer 인코딩으로 "인코딩된 메시지"의 끝부분에 위치한 헤더들의 목록 나열
Transfer-Encoding 메시지에 어떤 인코딩이 적용되었는지 수신자에게 알려줌
Upgrade 발송자가 업그레이드하길 원하는 새 버전이나 프로토콜
Via 어떤 중개자를 거쳤는지 (프록시, 게이트웨이 등)
일반 캐시 해더
참고로 HTTP/1.0부터 캐시가 도입되면서 일반 캐시 해더가 생겼다.
Cache-Control 메시지와 함깨 캐시 지시자를 전달하기 위해 사용
Pragma 캐시에 국한되지 않고, "지시자"를 전달함
- 요청 헤더 (Request Header)
req 측에만 존재하는 헤더이다. 클라이언트가 받고 싶은 데이터의 타입 등을 지정하는 Accept 헤더가 그 예이다.
Client-IP 클라이언트의 IP
From 사용자의 메일 주소
Host 대상 서버의 호스트 명과 포트
Referer 요청 URI가 들어있었던 문서의 URL을 제공
UA-Color, UA-CPU, UA-Disp, UA-OS, UA-Pixels 클라이언트 기기에 대한 정보들을 담음 각각 색상 능력, CPU, 디스플레이, OS, 픽셀 정보이다.
User-Agent 요청을 보낸 애플리케이션의 이름(브라우저, 기기 등)
Accept 관련 헤더
클라이언트는 자신이 무엇을 선호하고 수용가능한 지 서버에게 알려줄 수 있다. 이를 Accept 관련 헤더라고 한다.
Accept 서버가 보내도 되는 미디어 종류를 알려줌
Accept-Charset 서버가 보내도 되는 문자 집함을 알려줌
Accept-Encoding 서버가 보내도 되는 인코딩을 알려줌
Accept-Language 서버가 보내도 되는 언어를 알려줌
TE 서버가 보내도 되는 확장 전송 코딩을 알려줌
조건부 요청헤더
클라이언트는 요청에 조건을 달 수 있다. 특정 날짜 이후에 수정되었다면 요청을 받지 않거나 문서의 엔터티 태그가 주어진 엔터티 태그와 일치하지 않은 경우 요청을 제한하는 등이다. 이를 조건부 요청헤더라 부른다.
Expect 요청에 필요한 서버의 행동들을 열거할 수 있게 해준다.
If-Match 주어진 엔티티 태그가 , 문서의 엔티티 태그와 일치하는 경우에만 문서를 가져옴
If-Modified-Since 주어진 날짜 이후에 변경되지 않은 리소스에 대해서는 요청을 제한
If-None-Match If-Match와 반대
If-Range 문서의 특정 범위에 대한 요청
If-Unmodified-Since 주어진 날짜 이후에 변경된 리소스에 대해서는 요청 제한
Range 서버가 범위 요청을 지원하면, 리소스에 대한 특정 범위를 요청
요청 보안 헤더
요청 보안 헤더는 클라이언트가 어느 정도의 리소스에 접근하기 전에 자신을 인증하게 함으로써 트랜잭션에 안전성을 더 한다.
Authorization 클라이언트가 서버에게 제공하는 인증 그 자체에 대한 정보를 담고 있음
Cookie 서버에게 토큰을 전달할 때 사용
Cookie2 요청자가 지원하는 쿠키의 버전을 알려줌
프락시 요청 헤더
Max-Forwards 프락시나 게이트웨이를 탈 수 있는 최대 횟수
Proxy-Authorization Authorization 과 같으나, 프락시에서 인증할 때 사용
Proxy-Connection Connection과 같으나, 프락시에서 연결을 맺을 때 사용
- 응답 헤더 (Response Header)
res가 보내는 헤더이다. 서버의 정보를 주로 담는다. Server 헤더의 경우 무슨 웹 서버를 이용하고 있는 지에 대한 정보가 담겨있다.
Age 응답이 얼마나 오래되었는가
Public 특정 리소스에 대해 지원하는 요청 메서드의 목록
Retry-After 리소스가 사용 불가능일때, 언제부터 가능한지를 제공
Server 서버 애플리케이션의 이름과 버전
Title HTML문서에서 주어진 것과 같은 제목
Warning 사유 구절에 있는 것보다 더 자세한 경고메시지
협상 헤더
Accept-Ranges 서버가 자원에 대해 받아들일 수 있는 범위의 형태
Vary 서버가 확인해보아야 하고, 그래서 응답에 영향을 줄 수 있는 헤더들의 목록...(?)
응답 보안 헤더
Proxy-Authenticate 프락시에서 클라이언트로 보낸 인증요구 목록
Set-Cookie 서버가 클라이언트를 인증할 수 있도록 클라이언트 측에 토큰을 설정하기 위해 사용
Set-Cookie2
WWW-Authenticate 서버가 클라이언트로 보낸 인증요구 목록
- 엔터티 헤더 (Entity header)
엔터티 헤더는 엔터티 본문에 대한 헤더이다. 엔터티 본문에 보내는 데이터의 타입이 무엇인지 알려주는 Content-Type이나 데이터의 길이를 알려주는 Content-Length 등이 그 예이다.
Content-Base 바디에서 사용된 URL 의 Base URL
Content-Encoding 바디의 인코딩 타입
Content-Language 바디에 적절한 자연어
Content-Length 바디의 사이즈
Content-Location 리소스가 실제 어디에 위치하는가
Content-MD5 바디의 MD5체크섬
Content-Range 전체 리소스에서 이 엔티티가 해당하는 범위를 바이트 단위로 표현
Content-Type 바디가 어떤 종류의 객체인가
엔티티 캐싱헤더
일반 캐싱 헤더는 언제 어떻게 캐싱되어야 하는지에 대한 지시자를 제공하고, 엔티티 캐싱헤더는 엔티티 캐싱에 대한 정보를 제공(캐시된 사본이 유효한가?, 캐시된 리소스가 언제 expire 되는가 등등)
ETage 이 엔티티에 대한 엔티티 태그
Expires 이 엔티티가 더이상 유효하지 않아서 원본을 다시 받아와야 하는 시간
Last-Modified 가장 최근에 이 엔티티가 변경된 시간
- 확장 헤더
승인된 HTTP 명세서에는 추가되지 않은 비표준 헤더.
'🌐 Network > 🔗 HTTP' 카테고리의 다른 글
II. HTTP 아키텍처 | 5. 웹 서버 (0) | 2020.04.01 |
---|---|
I. HTTP: 웹의 기초 | 4. 커넥션 관리 (0) | 2020.04.01 |
I. HTTP: 웹의 기초 | 1. HTTP 개관, 2. URL과 리소스 (0) | 2020.03.31 |
[Cookie] Cookie (0) | 2020.03.27 |
[Buffer] 청크, 버퍼, 스트림 (1) | 2020.03.07 |