kakasoo

[HTTP] 6. 메서드 (Method) 본문

프로그래밍/HTTP

[HTTP] 6. 메서드 (Method)

카카수(kakasoo) 2020. 10. 17. 15:54
반응형

3.2 메시지의 각 부분

HTTP 메시지는 단순히 구조화된 블록이다. 각 메시지는 클라이언트로부터 요청, 서버로부터의 응답 중 하나를 포함한다. 메시지는 시작줄, 헤더 블록, 본문, 이렇게 세 부분으로 되어 있다.

시작줄은 이것이 어떠한 메시지인지에 대한 메타 정보를 담고 있고, 헤더 블록은 속성을, 본문은 데이터를 담고 있다. 본문은 없을 수도 있다.

시작줄과 헤더의 구분은 사실, 그저 캐리지 리턴개행 문자로 구성되어 있다. 다만 오래된 HTTP 어플리케이션이나 잘못 만든 HTTP 어플리케이션은 개행문자만으로 되어 있어 있는 경우도 있으니 그냥 개행문자만도 처리할 수 있어야 한다.

HTTP/1.0 200 OK            // 시작줄
Content-type: text/plain   // 헤더
Content-Length: 19         // 헤더
Hi! I'm a message!         // 본문

3.2.1 메시지 문법

모든 HTTP는 요청 또는 응답이다. 요청은 서버로 어떤 동작을 요구하고, 응답은 그 결과를 반환한다. 요청과 응답은 기본 구조가 같다.

// 요청
GET /specials/saw-blade.gif HTTP/1.0  // 메서드, 요청 URL, 버전
HOST: www.joes-hardware.com           // 헤더
                                      // 헤더와 본문 사이에는 공백 라인(CRLF)가 있다.
                                      // 본문

// 응답
HTTP/1.0 200 OK                       // 버전, 상태코드, 사유구절
Content-Type: image/gif               // 헤더
Content-Length: 8572
                                      // 헤더와 본문 사이에는 공백 라인(CRLF)가 있다.
                                      // 본문

요청은 위와 같이 메서드, 요청 URL, 버전과, 헤더, 엔터티 본문으로 구성되고, 응답은 버전과 상태코드, 사유구절, 헤더, 엔터티 본문으로 구성된다. 보다시피 첫번째 줄만이 다르다.

메서드는 클라이언트가 서버에 요구하는 것으로, GET, HEAD, POST 등의 한 단어로만 구성이 되어 있다. 요청 URL은 리소스를 지칭하는 완전한 URL, 혹은 경로 구성 요소를 의미한다.

버전은 HTTP/<메이저><마이너>의 형식을 따르며, 메이저와 마이너는 모두 정수이다. 상태코드는 요청 중에 일어난 것을 설명하는 세 자리 숫자이다. 첫번째 자릿수는 상태의 일반적인 분류로, 성공 또는 에러 등을 나타낸다.

사유구절은 숫자로 된 상태코드를 설명해주는 짧은 문구다, 사실 사유구절은 읽히기 위해 존재하는 텍스트일 분, 아무런 의미를 가지지 못한다. 만약 상태코드가 동등하게 200이면 하나는 OK, 하나는 NOT OK여도 둘은 성공한 것으로 본다.

헤더 는 이름, 콜론, 선태적인 공백, 값, CRLF가 순서대로 나타나는 것으로, 없을 수도 있다. 다만 HTTP/1.1 같은 몇몇 버전에서는 반드시 포함되는 헤더 종류가 있다.

마지막으로 엔터티 본문은 임의의 데이터 블록을 포함한다. 메시지는 없을 수도 있고, 이런 경우 헤더와 본문 사이의 공백 라인이었던 CRLF로 끝나게 된다. 즉, 본문이 없어도 CRLF로 끝난다.

다만 많은 구현체가 이것을 잊곤 하니, 클라이언트와 서버는 CRLF가 없는 경우도 고려하여 만들어져야 한다, 각각의 요소에 대한 자세한 설명은 해당 챕터에서 이어서.

3.2.2 시작줄

모든 HTTP 메시지는 시작줄로 시작한다. 요청은 무엇을 해야 하는지, 응답은 무엇이 일어났는지를 담고 있다. 위에도 언급했지만, 아래처럼 풀어서 이야기해보자.

요청줄은 어떤 동작을 해야 하는지, 그것이 어디에 있는지를 지칭하는 요청 URL, 클라이언트가 어떤 HTTP 버전으로 말하고 있는지를 서버에 알려주는 HTTP 버전을 포함한다. 각각의 필드는 공백문자로 구분된다.

응답줄은 수행결과에 대한 상태 정보, 결과 데이터를 클라이언트에게 준다. 시작줄 혹은 응답줄에는, 응답 메시지에 쓰인 HTTP의 버전, 숫자로 된 상태 코드, 수행 상태를 설명하는 사유 구절이 있다. HTTP/1.0 이전에는 없었다.

요청줄은 메서드로 시작하는데, HTTP 명세는 공통 요청 메서드의 집합을 정의한다, 예를 들면,

  • GET : 서버에서 어떤 문서를 가져온다.
  • HEAD : 서버에서 어떤 문서의 '헤더'만 가져온다.
  • POST : 서버에서 처리해야 할 데이터를 보낸다. 당연히 메시지의 본문을 가진다.
  • PUT : 서버에서 요청 메시지의 본문을 저장한다. 당연히 메시지의 본문을 가진다.
  • TRACE : 메시지가 프락시를 거쳐 서버에 도달하는 과정을 추적한다.
  • DELETE : 서버에서 문서를 제거한다.

이 메서드들은 쓸 수도 안쓸 수도 있고, HTTP 자체가 추가적인 메서드를 구현할 수 있어서, 새로운 메서드를 정의할 수도 있다. 이런 경우에는 확장 메서드라고 부른다.

상태 코드 는 무엇이 일어났는지를 말한다. 사유구절이 사람에게 이해하기 편하다면, 컴퓨터가 처리하기에는 숫자가 더 좋다. 상태 코드를 확장할 경우에는 일반적인 이해 범주로 담아야 한다. (ex. 성공한 경우면 2로 시작해야 한다.)

사유구절은 상태코드와 일대일로 대응한다, 다만 어떠한 규칙도 없으며, 아무런 영향도 가지지 못한다, 그저 상태 코드를 보다 쉽게 이해하기 위한 메시지일 뿐이다.

버전 번호는 HTTP/x.y 형식으로 기술되며 자신의 프로토콜 버전을 상대에게 알려준다. 이는 서로 불가능한 기능을 사용하지 않으려는 배려이다. 오해하지 말아야 하는 것은 각자 자신이 이해할 수 있는 버전 한계를 말한다는 점이다.

이것을 상대가 준 메시지의 버전이라고 생각해선 안 된다.

3.2.3 헤더

HTTP 헤더 명세는 여러 헤더 필드를 정의한다. 애플리케이션은 자신만의 헤더를 만들 수도 있다. 분류는 아래와 같다.

일반 헤더 는 요청과 응답 양쪽에 모두 나타낼 수 있다.

요청 헤더 요청에 대한 부가 정보를 나타낸다.

응답 헤더 응답에 대한 부가 정보를 나타낸다.

Entity 헤더 는 본문 크기와 콘텐츠, 혹은 리소스 그 자체를 서술한다. Entity에 대한 의미는 별도 정리하겠다.

확장 헤더 는 명세에 정의되지 않은 새로운 헤더를 의미한다.

헤더는 키와 값으로 이루어진 한 쌍으로 이루어지며 한 줄로 표현되지만, 만일 너무 길다면 개행을 하되 하나의 스페이스 이상의 들여쓰기를 통해 앞 헤더의 연장선임을 표현해주어야 한다.

3.2.4 엔터티 본문

HTTP 메시지의 세 번째 부분은 선택적인 엔티티 본문이다. 이는 HTTP 메시지의 화물, 또는 옮기고자 하는 것 그 자체이다.

3.2.5 버전 0.9 메시지

HTTP/0.9는 HTTP 프로토콜의 초기 버전이다. 요청은 그저 메서드와 URL만을 가지고 있고 응답은 본문만을 가진다. 매우 단순한 구조로 이루어져 있어서 많은 상황에 대응할 수는 없지만, 여전히 구식 클라이언트, 서버 등이 있으니 주의.

3.3 메서드

모든 서버가 모든 메서드를 구현하지는 않는다. 기본적으로 서버는, 자신의 리소스에 대한 GET, POST 메서드만 구현해도 충분하다. 메서드들은 별도의 제한을 가질 수도 있다.

가령 DELETE 메서드를 구현한 서버는, 어떠한 리소스든 삭제할 수 있게 하는 것을 원치 않을 것이다. 이러한 제한은 후술한다.

3.3.1 안전한 메서드(Safe Method)

HTTP는 안전한 메서드라 불리는 메서드의 집합을 정의한다. GET과 HEAD 메서드는 안전한 메서드인데, 이는 두 메서드가 서버에 어떠한 작용도 없음을 의미한다. (웹 개발자가 의도적으로 작용을 만들 수는 있다.)

안전한 메서드의 목적 (안전한 메서드를 구분하는 목적)은, 서버에 영향을 줄 수 있는 메서드를 사용할 때, 사용자에게 그 사실을 알려줄 수 있는 HTTP 애플리케이션을 만들 수 있도록 함이다.

3.3.2 GET

가장 흔히 쓰이는 메서드. 리소스를 요청하기 위해 쓰인다.

3.3.3 HEAD

GET 방식과 같지만 본문을 제외하고 헤더만을 가져온다는 차이가 있다. 이를 통해서 아래의 효과를 볼 수 있다.

  • 리소스를 가져오지 않고도 메타 데이터를 얻을 수 있다.
  • 개체의 존재 여부를 확인할 수 있다.
  • 리소스가 변경되었는지 검사할 수 있다.

서버 개발자들은 HEAD 메서드가 주는 정보가, GET 메서드가 주는 정보의 헤더와 정확히 일치하도록 설계해야 한다.

service.use(function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Methods", "GET,HEAD,OPTIONS,POST,PUT");
    res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");
    next();
  });

3.3.4 PUT

PUT 메서드는 서버에 문서를 쓴다. PUT으로 웹 페이지를 만들고 서버에 게시하도록 하는 것도 가능하다. PUT의 의미는 서버가, 요청의 본문을 가지고, 요청 URL의 이름대로 새 문서를 만들거나 교체하도록 하는 것이다.

PUT은 콘텐츠를 변경할 수 있도록 해주기 때문에, 많은 웹 서버가 PUT을 수행하기 전에 로그인을 요구한다.

3.3.5 POST

POST메서드는 서버에 입력 데이터를 전송하기 위해 설계되었다. POST는 서버에 데이터를 보내는 용도, PUT은 서버에 이미 있는 리소스에 데이터를 입력하기 위한 용도라고 보면 된다.

HTML에서는 폼을 지원하기 위해 사용되는데, 폼에 채워진 정보는 그대로 서버에 전송되고, 서버는 이를 필요로 하는 곳에 보낸다. (ex. 서버 게이트웨이 프로그램)

3.3.6 TRACE

클라이언트가 어떤 요청을 할 때, 그 요청은 방화벽, 프락시, 게이트웨이 등의 애플리케이션을 통과할 수 있다. 이들에게는 원래의 HTTP 요청을 수정할 수 있는 기회가 있다.

TRACE 메서드는 클라이언트에게 자신의 요청이 서버에 도달했을 때 어떻게 보이게 되는지 알려준다. TRACE 요청은 목적지 서버에서 루프백(Loopback) 진단을 시작한다.

전송의 마지막 단계에 있는 서버가 자신이 요청 받은 메시지를 본문에 넣어 그래도 돌려준다. 그 중간 지점과 첫 클라이언트들은, 다시 자신이 보낸 요청의 결과를 일일히 확인할 수 있게 된다.

다만 TRACE 메서드는 다른 메서드들에 대한 구분을 두지 않고 일관되게 다루지는 못한다.

3.3.7 OPTIONS

OPTIONS 메서드는 웹 서버에게 여러 가지 종류의 지원 범위에 대해 물어본다. 서버는 특정 리소스에 대해 어떤 메서드가 가능한지 물어볼 수 있다.

HTTP/1.1 200 OK
Allow: GET, POST, PUT, OPTIONS
Context-length: 0

3.3.8 DELETE

DELETE 메서드는 삭제를 요청하는 메서드다. 하지만 삭제가 수행되는 것을 보장 못한다. 명세에서는 서버가 클라이언트에게 아무런 알림없이 요청을 무시하는 것을 허락하기 때문이다.

3.3.9 확장 메서드

HTTP는 필요에 따라 확장해도 문제가 없도록 설계되어 있어서, 새로운 기능을 추가해도 문제가 되진 않는다. 다만, 확장 메서드는 명세에는 정의되지 않아 있다. 아래처럼 만들어진 메서드들이 있다.

  • LOCK : 사용자가 리소스를 잠근다.
  • MKCOL : 사용자가 문서를 생성할 수 있게 해준다.
  • COPY : 서버에 있는 리소스를 복사한다.
  • MOVE : 서버에 있는 리소스를 옮긴다.

모든 확장 메서드가 형식을 갖춘 명세로 정의되지는 않으므로 주의해야 한다. 만약 본인이 만들 경우에도 마찬가지다. 본인이 만든 메서드를 이해하지 못하는 애플리케이션이 있을 수도 있다.

그러므로 확장 메서드는 최대한 관용적으로 만들어야 한다. 이를 존중하여, 만약 메서드가 종단 간 (end-to-end principle)을 망가뜨리지 않는다면 프락시는 메서드를 전달해줄 것이고, 반대의 경우에는 501을 보낼 것이다.

상태코드 501은 요청을 처리할 수 없다는 의미다, 즉 메서드를 알 수 없다는 의미로서 반환되는 것이다.

be conservative in what you send, be liberal in what you accept, 엄격하게 보내고 관대하게 받아들이라는 Postel의 법칙을 따르자.

반응형

'프로그래밍 > HTTP' 카테고리의 다른 글

[HTTP] 8. 헤더 (Headers)  (0) 2020.10.18
[HTTP] 7. 상태코드 (Status Code)  (0) 2020.10.18
[HTTP] 5. 메세지 (Message)  (0) 2020.10.17
[HTTP] 4. URL  (0) 2020.10.11
트랜잭션 ( Transaction )  (0) 2020.10.08